Tags: FFT KMP Border
对于一个长度为n的字符串。
border
很好这个(对我来说)新奇的东西把我这种什么都不会的苣蒻淘汰下去了。
这个东西来自KMP算法。暂且不考虑和KMP算法的联系,单单来看border的性质有什么呢。
以下内容全部来自这篇题解
定理内容:
s[1,i]=s[n−i+1,n] s [ 1 , i ] = s [ n − i + 1 , n ] 其实就是对于s有长度为(n-i)的循环节 (最后一个循环节不需要完整)推论1
对于任意的i满足 si=sn−i+1 s i = s n − i + 1
推论2
如果s不存在长度为d的循环节,那么长度为d的倍数的循环节也一定不存在
推论3
如果对于所有的d,所有长度为d的因数的循环节都存在,那么一定存在长度为d的循环节。
然后根据推论2和推论3就可以完成这道题了。
首先找出所有的01对,记录两者的距离d,那么就不存在长度为d的倍数的循环节。
然后首先找出所有的d,然后再用类似埃氏筛的方法就可以把所有的循环节找出来了。
但是对于暴力找所有的01对,复杂度是 n2 n 2 的,这里可以通过fft或者ntt来优化一下,快速求出所有距离是否存在01对。
以下是AC了之后的扯淡。
知道这个东西的性质之后其实还是蛮水的,但是不知道的话当场推好像还是稍微有点难度啊qwq?
然后就是写了最后一挡之后的确很好用fft优化,但是也很容易因为各种原因挂掉诶?(挂了一次)
#include
#define M 2000005
#define db double
#define ll long long
using namespace std;
struct Complex{
db r,i;
Complex(db R=0,db I=0){
r=R; i=I;
}
};
Complex operator +(const Complex &x,const Complex &y){
return Complex(x.r+y.r,x.i+y.i);
}
Complex operator -(const Complex &x,const Complex &y){
return Complex(x.r-y.r,x.i-y.i);
}
Complex operator *(const Complex &x,const Complex &y){
return Complex(x.r*y.r-x.i*y.i,x.r*y.i+x.i*y.r);
}
Complex operator / (const Complex &x,const int &y){
return Complex(x.r/y,x.i/y);
}
int flag[M],n;
char s[M];
const db pi=acos(-1.0);
struct FFT{
Complex A[M],B[M];
int rev[M];
void solve(Complex *a,int n,int DFT){
register int i,j,k,m;
Complex l,r,w,wn;
for (i=0;iif (ifor (m=1;m1){
k=(m<<1);
w=Complex(1,0);
wn=Complex(cos(pi*DFT/m),sin(pi*DFT/m));
for (i=0;ifor (j=i;jif (DFT==-1){
for (i=0;ivoid solve(int *a,int *b,int n){
int i,k;
for (k=1;k1);
for (i=0;i0);
B[i]=Complex(b[i],0);
rev[i]=(rev[i>>1]>>1)|((i&1)*(k>>1));
}
solve(A,k,1); solve(B,k,1);
for (i=0;i1);
for (i=0;iint)(A[i].r+0.5);
}
}
}fft;
int a[M],b[M];
int main(){
// freopen("1.in","r",stdin);
scanf("%s",s+1);
n=strlen(s+1);
int i,j;
ll res=0;
for (i=1;i<=n;i++){
if (s[i]=='1')a[i]=1;
if (s[i]=='0')b[n-i]=1;
}
fft.solve(a,b,2*n+5);
for (i=0;i0;
}
for (i=1;i<=n;i++)if (!flag[i]){
for (j=i+i;j<=n;j+=i){
flag[i]|=flag[j];
}
}
for (i=1;i<=n;i++){
res^=1ll*i*i*(1-flag[n-i]);
}
printf("%lld\n",res);
return 0;
}