- 给定一个长度为(n)的(01)串,其中有一些字符缺失了。
- 对于每一个(i),问是否存在一种填法使得长度为(i)的前缀与长度为(i)的后缀相同。
- (nle5 imes10^5)
一年前曾开过这道题,当时有个脑瘫的想法,调了半天才发现问题,一怒之下就弃了。
一年后又开了这道题,又先有了当时那个脑瘫的想法,结果再次想了半天才重新发现问题,看来一年来实力毫无长进。。。
(border)的性质
对于一个长度为(i)的前缀,如果它与长度为(i)的后缀相同,我们称其为一个(border)。
(border)有一个基本性质,就是长度为(i)的前缀是(border),充要于(n-i)是该字符串的一个周期。
这个性质的证明,只要自己画下图,分前缀和后缀重叠与不重叠两类讨论一下就行了。
解题思路
考虑如果(i)可能成为(border),就是要判断(n-i)是否可能成为周期。
也就是说,不能存在两个(0,1),满足它们的下标之差是(n-i)的倍数。
因此我们令(a_i)表示(s_i)是否为0
,(b_i)表示(s_{n-i+1})是否为1
。
那么只要((a*b)[n-x+1] ot=0)或((a*b)[n+x+1] ot=0),就说明存在两个(0,1)下标之差为(x),则周期(x)非法。
然后再对于每一个可能的周期,去看一下它的倍数中是否有非法的,如果有那么它也非法了。
代码:(O(nlogn))
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 500000
#define DB double
using namespace std;
int n,a[2*N+5],b[N+5],p[N+5];char s[N+5];
namespace Poly//多项式乘法
{
int P,L,R[N<<2];DB Pi=acos(-1);
struct node
{
DB x,y;I node(Con DB& a=0,Con DB& b=0):x(a),y(b){}
I node operator + (Con node& o) Con {return node(x+o.x,y+o.y);}
I node operator - (Con node& o) Con {return node(x-o.x,y-o.y);}
I node operator * (Con node& o) Con {return node(x*o.x-y*o.y,x*o.y+y*o.x);}
}A[N<<2],B[N<<2];
I void FFT(node* s,CI op)
{
RI i,j,k;node U,S,x,y;for(i=0;i^P;++i) i<R[i]&&(x=s[i],s[i]=s[R[i]],s[R[i]]=x,0);
for(i=1;i^P;i<<=1) for(U=node(cos(Pi/i),op*sin(Pi/i)),j=0;j^P;j+=i<<1)
for(S=1,k=0;k^i;++k,S=S*U) s[j+k]=(x=s[j+k])+(y=S*s[i+j+k]),s[i+j+k]=x-y;
}
I void Mul(int* a,int* b)//卷积
{
RI i;P=1,L=0;W(P<=(n<<1)) P<<=1,++L;for(i=0;i^P;++i) R[i]=(R[i>>1]>>1)|((i&1)<<L-1);
for(i=1;i<=n;++i) A[i]=a[i],B[i]=b[i];FFT(A,1),FFT(B,1);
for(i=0;i^P;++i) A[i]=A[i]*B[i];for(FFT(A,-1),i=1;i<=2*n;++i) a[i]=A[i].x/P+0.5;
}
}
int main()
{
RI i,j;for(scanf("%s",s+1),n=strlen(s+1),i=1;i<=n;++i) a[i]=s[i]=='0',b[n-i+1]=s[i]=='1';//初始化
for(Poly::Mul(a,b),p[0]=1,i=n;i;--i)
for(p[i]=!a[n-i+1]&&!a[n+i+1],j=i<<1;p[i]&&j<=n;j+=i) p[i]&=p[j];//如果倍数中有非法的,它也非法了
long long t=0;for(i=1;i<=n;++i) p[n-i]&&(t^=1LL*i*i);return printf("%lld
",t),0;//i是border充要于n-i是周期
}