题目
T1
T2
T3
总结
今天考得不好,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大爷的证明方法:
我们可以想象成往空串中放字符,而且要保证
- 从任意某处切开,左右两边至少有一个回文串。
- 整个串是是回文串。
不妨先在左边第一个位置填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
首先,经典套路最小割=最大流,现在考虑怎么构图。
有两种思路:
- 每个点拆成+w和-w两个点,一个连S,一个连T,但这题没这个必要;
- 每个点与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):
- 0 < x < a 0<x<a 0<x<a:此时这个块两个人都不能选,不会对结果造成影响;
- a ≤ x < b a\leq x<b a≤x<b:这个块只有A能选,如果出现了这个块,那么A必胜;
- b ≤ x < 2 a b\leq x<2a b≤x<2a:这个块A和B都只能选一次,它的作用就是改变先后手;
- 2 a ≤ x 2a\leq x 2a≤x:这个块如果被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,i是奇数cnt3Ccnt3i,g=∑i=0,2∣icnt3Ccnt3i
考虑后手必胜的情况,这是改变偶数次先后手的必然结果,因此答案 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+f⋅cnt4)。
考虑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=2n−ans1−ans2。
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;
}