ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

模拟88 考试总结

2021-11-03 14:31:06  阅读:148  来源: 互联网

标签:const int 枚举 88 模拟 jcny inline 考试 mod


崩陨

考试经过

啥也不会,T1想了半天差点睡着,然后狂打暴力
最后出来T1dp假了,T3模数是993244853,根本无法评价
垫底了,然后自闭一天,啥也没干,旁边人切掉了\(10^9+7\)道题,我啥也不会

T1.按位或

暴力基本和正解关系不大,然而我想了一个极其复杂的\(n^3\)还假了
正解在于容斥,%%%容斥带师WYZG
假如不管3的倍数的限制,那么可以直接按照答案的位考虑,一个\(log\)轻松出结果
然而有了限制就不好玩了,发现2的若干次幂模3余数只能是1或2,那么可以用这个性质搞一下
设\(p_i\)表示至少有\(i\)位的1不选的方案数,那么是一个经典的奇加偶减的形式,答案即恰好\(0\)位不选
注意到这里并不能直接简单的组合数,因为我们还要保证所有数都是3的倍数
发现二进制下奇数位的1余数是1,偶数位的余数是2,那么可以枚举一下这\(i\)位中在奇数和偶数位的1的个数
这里又是一个\(log\),枚举之后剩下的就可以直接随便选/不选了,我们做一个简单的dp来确定最后的方案数
\(f_{i,j}\)表示已经确定了\(i\)位,余数是\(0/1/2\)的方案数,枚举这一位选不选1转移即可
由于\(n\)个都等价所以快速幂,由于从奇数偶数位中分别要选出来,所以乘两个组合数,也很好理解
所以\(log^3\)就做完了,发现其实不难,只是脑子瓦特了

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
const int N=65;
int n,t,c[N][N];
inline int ksm(int x,int y)
{
	int s=1;x%=mod;
	for(;y;y>>=1)
	{
		if(y&1)s=s*x%mod;
		x=x*x%mod;	
	}
	return s;
}
int f[N][3];
signed main()
{
	freopen("or.in","r",stdin);
	freopen("or.out","w",stdout);
	cin>>n>>t;
	int s1=0,s2=0,s=0;
	while(t)
	{
		s++;
		if(t&1)
		{
			if(s&1)s1++;
			else s2++;
		}
		t>>=1;
	}
	c[0][0]=1;
	for(int i=1;i<=64;i++)
	{
		c[i][0]=1;
		for(int j=1;j<=i;j++)c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
	}
	int ans=0;
	for(int i=0;i<=s1+s2;i++)
	{
		int sum=0;
		for(int j=max(i-s2,(int)0);j<=s1;j++)
		{
			int p1=s1-j,p2=s2-(i-j);
			assert(p1>=0);assert(p2>=0);
			memset(f,0,sizeof(f));
			f[0][0]=1;
			for(int i=0;i<p1;i++)for(int j=0;j<=2;j++) 
			{
				f[i+1][j]=(f[i+1][j]+f[i][j])%mod;
				f[i+1][(j+1)%3]=(f[i+1][(j+1)%3]+f[i][j])%mod;
			}
			for(int i=p1;i<p1+p2;i++)for(int j=0;j<=2;j++)
			{
				f[i+1][j]=(f[i+1][j]+f[i][j])%mod;
				f[i+1][(j+2)%3]=(f[i+1][(j+2)%3]+f[i][j])%mod;
			}
			sum=(sum+ksm(f[p1+p2][0],n)*c[s1][j]%mod*c[s2][i-j]%mod)%mod;
		}
		if(i&1)ans=(ans-sum+mod)%mod;
		else ans=(ans+sum)%mod;
	}
	cout<<ans<<endl;
	return 0;
}

T2.最短路径

考场上根本没好好想,其实也不算很难
考虑选出\(k\)个点的最优策略,发现如果朴素一点是任选一个起点,每次走到一个点回到起点
发现不一定要每次回去,事实上应该是选择一条主路走到头,别的分叉往回走,感性理解一下
显然这个主路只走一遍,别的走两遍,那么应该选直径
因此就是任意两点距离之和2倍减去直径长度,虚树啥的咱也不懂
但题目算的期望,所以直接枚举肯定不行,考虑拆开算每条路径的贡献
对于前者,枚举每条路径,他贡献的概率就是点在两边的概率,可以用总的方案数减去不合法(点在一边)的概率
后者直接枚举直径端点,考虑另外的点能否合法从而使它成为直径
合法的条件就是不存在距离小于他,或者距离相等但是标号小
然后直接枚举就好了,乘上\(cnt-2\)选\(k-2\)的概率,\(cnt\)是合法点数,复杂度\(m^3\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2050;
const int mod=998244353;
struct node{
	int from,to,next;
}a[2*N];
int head[N],mm=1;
inline void add(int x,int y)
{
	a[mm].from=x;a[mm].to=y;
	a[mm].next=head[x];head[x]=mm++;
}
inline int ksm(int x,int y)
{
	int s=1;x%=mod;
	for(;y;y>>=1)
	{
		if(y&1)s=s*x%mod;
		x=x*x%mod;
	}
	return s;
}
inline int ny(int x){return ksm(x,mod-2);}
int jc[N],inv[N],jcny[N],n,m,k;
inline void pre()
{
	jc[0]=jc[1]=inv[1]=jcny[0]=jcny[1]=1;
	for(int i=2;i<=n;i++)
	{
		jc[i]=jc[i-1]*i%mod;
		inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		jcny[i]=jcny[i-1]*inv[i]%mod;
	}	
}
inline int C(int x,int y)
{
	if(x<y)return 0;
	if(!y)return 1;
	return jc[x]*jcny[y]%mod*jcny[x-y]%mod;
}
int d[N],fa[N],size[N],son[N],ss[N];
int top[N],ans,pp[N];bool v[N];
void dfs1(int x)
{
	v[x]=1;
	for(int i=head[x];i;i=a[i].next)
	{
		int y=a[i].to;
		if(v[y])continue;
		d[y]=d[x]+1;fa[y]=x;
		dfs1(y);size[x]+=size[y];ss[x]+=ss[y];
		ans=(ans+(1ll-((C(ss[y],k)+C(m-ss[y],k))%mod*ny(C(m,k))%mod)+mod)%mod*2%mod)%mod;
		if(size[y]>size[son[x]])son[x]=y;
	}
	size[x]++;
	ss[x]+=pp[x];
}
void dfs2(int x,int h)
{
	if(!x)return;
	v[x]=1;top[x]=h;
	dfs2(son[x],h);
	for(int i=head[x];i;i=a[i].next)
	{
		int y=a[i].to;
		if(v[y]||y==son[x])continue;
		dfs2(y,y);
	}
}
inline int getlca(int x,int y)
{
	int fx=top[x],fy=top[y];
	while(fx!=fy)
	{
		if(d[fx]<d[fy])swap(x,y),swap(fx,fy);
		x=fa[fx],fx=top[x];
	}
	if(d[x]<d[y])swap(x,y);
	return y;
}
inline int getd(int x,int y)
{
	int lca=getlca(x,y);
	return d[x]+d[y]-2*d[lca];
}
int p[N];
signed main()
{
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	cin>>n>>m>>k;
	for(int i=1;i<=m;i++)scanf("%lld",&p[i]),pp[p[i]]=1;
	sort(p+1,p+1+m);
	for(int i=1;i<n;i++)
	{
		int x,y;scanf("%lld%lld",&x,&y);
		add(x,y);add(y,x);
	}
	pre();d[1]=1;dfs1(1);
	memset(v,0,sizeof(v));dfs2(1,1);
	for(int i=1;i<=m;i++)for(int j=i+1;j<=m;j++)
	{
		int x=p[i],y=p[j];if(x>y)swap(x,y);
		int dis=getd(x,y),sum=0;
		for(int k=1;k<=m;k++)
		{	
			int z=p[k];if(z==x||z==y)continue;
			int d1=getd(z,x),d2=getd(z,y);
			if(d1>dis||(d1==dis&&z<y))continue;
			if(d2>dis||(d2==dis&&z<x))continue;
			sum++;
		}
		ans=(ans-C(sum,k-2)*ny(C(m,k))%mod*dis%mod+mod)%mod;
	}
	cout<<ans<<endl;
	return 0;
}

T3.仙人掌

RT,不可做,咕

T4.对弈

原题P2490
发现A只会向右走,B只会向左走,那么把两个棋子看成一堆数量为\(b_i-a_i-1\)的石子,那么通过颓题解可以看出这是一个k-nim模型
结论是先手必败当且仅当所有\(a_i\)变成二进制之后每一位上的1的个数都模\(m+1\)余0,证明见下
image
所以可以dp,设\(f_{i,j}\)表示考虑第\(i\)位,总和为\(j\)方案数,枚举是\(m+1\)的多少倍即可

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=100050;
const int mod=1e9+7;
int jc[N],inv[N],jcny[N],n,k,m;
int f[20][N];
inline void pre()
{
	jc[0]=jc[1]=inv[1]=jcny[0]=jcny[1]=1;
	for(int i=2;i<=n;i++)
	{
		jc[i]=jc[i-1]*i%mod;
		inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		jcny[i]=jcny[i-1]*inv[i]%mod;
	}	
}
inline int C(int x,int y)
{
	if(x<y)return 0;
	if(!y)return 1;
	return jc[x]*jcny[y]%mod*jcny[x-y]%mod;
}
signed main()
{
	freopen("chess.in","r",stdin);freopen("chess.out","w",stdout);
	cin>>n>>k>>m;pre();
	f[0][0]=1;int ans=0;
	for(int i=0;i<=12;i++)for(int j=0;j<=n-k;j++)
	{	
		for(int kk=0;j+kk*(1<<i)*(m+1)<=n-k&&kk*(m+1)<=k/2;kk++)
			f[i+1][j+kk*(1<<i)*(m+1)]=(f[i+1][j+kk*(1<<i)*(m+1)]+f[i][j]*C(k/2,kk*(m+1))%mod)%mod;
	}
	for(int i=0;i<=n-k;i++)ans=(ans+f[13][i]*C(n-i-k/2,k/2)%mod)%mod;
	cout<<(C(n,k)-ans+mod)%mod<<endl;
	return 0;
}

考试总结

这场又挂没,原因是多方面的,开始节奏就乱了,到后面也没回来
希望可以尽快走出来,毕竟联赛没几天了,考场上心态一定要把握好

标签:const,int,枚举,88,模拟,jcny,inline,考试,mod
来源: https://www.cnblogs.com/PMZG/p/15502992.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有