2020.09.12【省选组】模拟 比赛总结

题目

T1

gmoj 5505. 【清华冬令营2018模拟】串

T2

gmoj 5506. 【清华冬令营2018模拟】变量

T3

gmoj 5507. 【清华冬令营2018模拟】取石子


总结

今天考得不好,T1搞了很久才猜想出结论,T2死活构不出图。

一开始发现T3看起来比较容易,就先去做T3了。
因为取石子的过程中两人会在同一堆石子中轮流选很多轮,因此先将x模a+b。
接着考虑对于每一堆石子Alice和Bob分别先手,最后是谁赢,将其累积到Alice必胜、Bob必胜、先手必胜、后手必胜的四个统计变量里面。然后统计答案。
这个方法有不少情况没有考虑到,漏洞挺多的,于是20分。
接着去做T1(因为当时T2题面有争议),手玩了几下后感觉答案要么是-1和0、1,要么是2(即任意不是aaaaa…和ababa…、aaa…aabaa…aaa的回文串都可以找到一个位置 i ,使得 [ 1 , i ] 和 [ i+1 , n ] 都不是回文串)。
找不到反例(用了多种方法都构造不出反例),但是也不会证明,于是打了个暴搜。结果发现真的不存在小规模的反例,那么大规模的反例应该也是不存在的了。
特判0,1,-1的情况,其他情况都输出2即可。

剩下接近1.5个小时,我去想T2,感觉是网络流,但一直没有想到怎么构图,只好放弃。暴力写了出来,但是WA0了(某地方没加1LL* +循环范围搞错)……

总结:对于网络流等算法的思想掌握不够熟练!


题解

T1

这里提供YZY大爷的证明方法:

我们可以想象成往空串中放字符,而且要保证

  1. 从任意某处切开,左右两边至少有一个回文串。
  2. 整个串是是回文串。

不妨先在左边第一个位置填a,那么串为a……a。 第二个位置分两种情况讨论,跟第一个位置一样(即填a)或者不一样(不妨填b)。

  • 第二个位置填a:

    • 第三个位置填b: 那么就是aab……baa, 我们这样切开aab|……baa。 左边不是回文串,所以要使右边为回文串,即aab|aab……baa ( 回文串对称 ),
      那么我们这样切,aaba|ab……baa,会发现不满足条件2(因此可以切成2个非回文串)。
    • 第三个位置填a: 最后这个串就是aaa……aaa这样。 然而有唯一一种特殊情况。 aa……aabaa……aa 整个串长度为奇数,除了中间一个字符不同,其他都相同。 这时不能切成两个非回文串,因此这种情况对应-1。
  • 第二个位置填b: 类似的讨论,会发现只有ababababa这样一种合法情况,这种情况对应-1。


T2

首先,经典套路最小割=最大流,现在考虑怎么构图。
有两种思路:

  1. 每个点拆成+w和-w两个点,一个连S,一个连T,但这题没这个必要;
  2. 每个点与S、T连边,边权分别为+w的贡献和-w的贡献。

接着发现|w[xi]-w[yi]|只可能有2种取值:

  • 当w[xi]与w[yi]同号时,为0;
  • 当w[xi]与w[yi]异号时,为2w。

这就处理完了ai|w[xi]-w[yi]|+bi|w[yi]-w[zi]|+ci|w[zi]-w[xi]|这坨东西,而di(w[xi]-w[yi])+ei(w[yi]-w[zi])+fi(w[zi]-w[xi])则可以拆出w[xi],w[yi],w[zi]的系数,加到+w的贡献和-w的贡献上。

最棘手的是限制条件,但可以发现:

  • 若w[x]<=w[y],当w[y]=W时,w[x]可为正可为负;当w[y]=-W时,w[x]为负。即如果割了y->T的边,必须要割x->T的边,而割了y->T的边就会剩下S->y的边,因此连一条y->x的值为inf的边即可;
  • 若w[x]=w[y],这相当于w[x]<=w[y] , 且w[y]<=w[x],这就转化为了上一种情况;
  • 若w[x]<w[y],那么只能是w[y]=W,w[x]=-W,因此S->x和y->T的边不能割,就强制把它们的边权设定为inf。

把所有 S连出去的边 和 连向T的边 的边权加上一个较大的数,最后答案减去 n*这个数 即可解决负边权的问题。


T3

将每一块的x模上a+b,分成以下4类(不妨设a<b):

  1. 0 < x < a 0<x<a 0<x<a:此时这个块两个人都不能选,不会对结果造成影响;
  2. a ≤ x < b a\leq x<b ax<b:这个块只有A能选,如果出现了这个块,那么A必胜;
  3. b ≤ x < 2 a b\leq x<2a bx<2a:这个块A和B都只能选一次,它的作用就是改变先后手;
  4. 2 a ≤ x 2a\leq x 2ax:这个块如果被A选了1次,那么就变成了情况2,A必胜。因此A和B都要优先抢夺这个块。

c n t i cnt_i cnti表示第 i 类块的个数, f = ∑ i = 1 , i 是 奇 数 c n t 3 C c n t 3 i , g = ∑ i = 0 , 2 ∣ i c n t 3 C c n t 3 i f=\sum_{i=1,i是奇数}^{cnt_3}C_{cnt_3}^i,g=\sum_{i=0,2|i}^{cnt_3}C_{cnt_3}^i f=i=1,icnt3Ccnt3i,g=i=0,2icnt3Ccnt3i
考虑后手必胜的情况,这是改变偶数次先后手的必然结果,因此答案 a n s 1 = 2 c n t 1 g ans_1=2^{cnt_1}g ans1=2cnt1g
考虑先手必胜的情况,这是改变奇数次先后手,或出现了一个第4类块并改变偶数次先后手(此时如果是A先手就直接胜利了;而B先手就会抢夺第4类块,产生交换1次先后手的效果)的结果,因此答案 a n s 2 = 2 c n t 1 ( g + f ⋅ c n t 4 ) ans_2=2^{cnt_1}(g+f\cdot cnt_4) ans2=2cnt1(g+fcnt4)
考虑A(或B)必胜的情况,发现直接计算很麻烦,于是 a n s 3 = 2 n − a n s 1 − a n s 2 ans_3=2^n-ans_1-ans_2 ans3=2nans1ans2


CODE

T1

#include<cstdio>
using namespace std;
#define N 100005
char a[N];
int main()
{
    
    
	freopen("string.in","r",stdin);
	freopen("string.out","w",stdout);
	int n,t,i;
	scanf("%d",&t);
	while(t--)
	{
    
    
		scanf("%d%s",&n,a+1);
		if(!n){
    
    puts("0");continue;}
		for(i=1;i<=n>>1;++i) if(a[i]!=a[n-i+1]) break;
		if(i<=n>>1){
    
    puts("1");continue;}
		for(i=2;i<=n;++i) if(a[i]!=a[i-1]) break;
		if(i>n||i==n/2+1&&(n&1)){
    
    puts("-1");continue;}
		for(i=3;i<=n;++i) if(a[i]!=a[i-2]) break;
		if(i>n){
    
    puts("-1");continue;}
		puts("2");
	}
	return 0;
}

T2

#include<cstdio>
#include<cstring>
using namespace std;
#define ll long long
#define inf 999999999
#define add 1000000
#define M 1000005
#define N 505
#define S 501
#define T 502
int fir[N],to[M],nex[M],dis[N],gap[N],cur[N],s=1;
ll len[M],e[N][N],val[N];bool b1[N],b2[N];
inline void inc(int x,int y,int z)
{
    
    
	to[++s]=y,len[s]=z,nex[s]=fir[x],fir[x]=s;
	to[++s]=x,len[s]=0,nex[s]=fir[y],fir[y]=s;
}
int dfs(int u,int flow)
{
    
    
	if(u==T) return flow;
	int v,i,have=flow,tmp;
	for(i=cur[u];i;i=nex[i])
	{
    
    
		cur[u]=i,v=to[i];
		if(len[i]&&dis[u]==dis[v]+1)
		{
    
    
			tmp=dfs(v,have<len[i]?have:len[i]);
			have-=tmp,len[i]-=tmp,len[i^1]+=tmp;
			if(!have) return flow;
		}
	}
	cur[u]=fir[u];
	if(!--gap[dis[u]]) dis[S]=T;
	++gap[++dis[u]];
	return flow-have;
}
int main()
{
    
    
	freopen("variable.in","r",stdin);
	freopen("variable.out","w",stdout);
	int t,n,w,s,p,q,i,j,x,y,z,num;ll ans;
	scanf("%d",&t);
	while(t--)
	{
    
    
		scanf("%d%d%d%d",&n,&w,&p,&q);
		memset(fir,0,sizeof(fir));
		memset(gap,0,sizeof(gap));
		memset(dis,0,sizeof(dis));
		memset(val,0,sizeof(val));
		memset(b1,0,sizeof(b1));
		memset(b2,0,sizeof(b2));
		memset(e,0,sizeof(e));
		for(i=1;i<=p;++i)
		{
    
    
			scanf("%d%d%d%d",&x,&y,&z,&num);
			e[x][y]+=num<<1,e[y][x]+=num<<1,scanf("%d",&num);
			e[y][z]+=num<<1,e[z][y]+=num<<1,scanf("%d",&num);
			e[z][x]+=num<<1,e[x][z]+=num<<1,scanf("%d",&num);
			val[x]+=num,val[y]-=num,scanf("%d",&num);
			val[y]+=num,val[z]-=num,scanf("%d",&num);
			val[z]+=num,val[x]-=num;
		}
		for(i=1;i<=q;++i)
		{
    
    
			scanf("%d%d%d",&x,&y,&z);
			if(z==0) e[y][x]=inf;
			else if(z==1) e[x][y]=e[y][x]=inf;
			else b1[x]=1,b2[y]=1;
		}
		for(i=1;i<=n;++i)
			for(j=1;j<=n;++j)
				if(e[i][j]) inc(i,j,e[i][j]);
		for(i=1;i<=n;++i)
		{
    
    
			cur[i]=fir[i];
			inc(S,i,b1[i]?inf:val[i]+1+add);
			inc(i,T,b2[i]?inf:add-val[i]-1);
		}
		ans=0;while(dis[S]<T) ans+=dfs(S,inf);
		printf("%lld\n",(ans-1LL*add*n)*w);
	}
	return 0;
}

T3

#include<cstdio>
using namespace std;
#define P 1000000007
#define N 100005
inline char gc()
{
    
    
	static char buf[100005],*l=buf,*r=buf;
	return l==r&&(r=(l=buf)+fread(buf,1,100005,stdin),l==r)?EOF:*l++;
}
inline void read(int &k)
{
    
    
	char ch;
	while(ch=gc(),ch<'0'||ch>'9');k=ch-'0';
	while(ch=gc(),ch>='0'&&ch<='9') k=k*10+ch-'0';
}
int cnt[4],ans[3],fac[N],inv[N];
inline int pow(int x,int y)
{
    
    
	int s=1;
	while(y)
	{
    
    
		if(y&1) s=1LL*s*x%P;
		x=1LL*x*x%P,y>>=1;
	}
	return s;
}
inline int C(int x,int y){
    
    return 1LL*fac[x]*inv[y]%P*inv[x-y]%P;}
inline int add(int x,int y){
    
    x+=y;if(x>=P) x-=P;return x;}
int main()
{
    
    
	freopen("stone.in","r",stdin);
	freopen("stone.out","w",stdout);
	int n,a,b,i,x,tmp,f=0,g=0;bool flag=0;
	read(n),read(a),read(b);
	if(a>b) a^=b,b^=a,a^=b,flag=1;
	for(i=1;i<=n;++i)
	{
    
    
		read(x),tmp=x%(a+b);
		if(tmp<a) ++cnt[0];
		else if(a<=tmp&&tmp<b) ++cnt[1];
		else if(b<=tmp&&tmp<a<<1) ++cnt[2];
		else ++cnt[3];
	}
	fac[0]=1;for(i=1;i<=n;++i) fac[i]=1LL*fac[i-1]*i%P;
	inv[1]=1;for(i=2;i<=n;++i) inv[i]=1LL*inv[P%i]*(P-P/i)%P;
	inv[0]=1;for(i=1;i<=n;++i) inv[i]=1LL*inv[i-1]*inv[i]%P;
	for(i=0;i<=cnt[2];++i)
		i&1?f=add(f,C(cnt[2],i)):g=add(g,C(cnt[2],i));
	ans[0]=1LL*pow(2,cnt[0])*add(f,1LL*g*cnt[3]%P)%P;
	ans[1]=1LL*pow(2,cnt[0])*g%P;
	ans[2]=pow(2,n)-add(ans[0],ans[1]);
	if(ans[2]<0) ans[2]+=P;
	flag?printf("0 %d %d %d\n",ans[2],ans[0],ans[1]):printf("%d 0 %d %d\n",ans[2],ans[0],ans[1]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huangzihaoal/article/details/108554000
今日推荐