感觉border的性质还是挺神奇的
一个border的性质是$S$有长度为$len$的border当且仅当对$\forall i\equiv j\left(\bmod(n-len)\right)$有$S_i=S_j$,也就是说它有长度为$len-i$的循环节(末尾多出来的部分需要和开头一样),画个图就知道这个性质是对的
所以我们把整个字符串分成长度为$n-len$的许多组,记$\text{pre}_i=S_{1\cdots i},\text{suf}_i=S_{i\cdots n}$
一个结论是:如果不存在$(n-len)|i$使得$suf_{i+1}\ne pre_{n-i}$,那么存在长度为$len$的border(这里的“不等于”只考虑$1\ne0$的情况,不考虑问号)
我们来证明这个结论,如果存在$(n-len)|i$使得$\text{suf}_{i+1}\ne\text{pre}_{n-i}$,那么存在不相等的两组,所以不存在长度为$len$的border
否则对于$\forall(n-len)|i_1,i_2$,我们都有$S_{i_1-(n-len)+1\cdots i_1}=S_{i_2-(n-len)+1\cdots i_2}$,即是说$S$有长度为$n-len$的循环节,这就证明了它有长度为$len$的border
所以我们要做的就是快速判断$suf_{i+1}$是否等于$pre_{n-i}$,直接用正串的0和反串的1做卷积即可,最后枚举$len$和$n-len$的倍数判断,总时间复杂度$O(n\log_2n)$
#include<stdio.h> #include<math.h> #include<string.h> typedef double du; const int maxn=1048576; const du eps=1e-7; typedef long long ll; struct complex{ du x,y; complex(du a=0,du b=0){x=a;y=b;} }; complex operator+(complex a,complex b){return complex(a.x+b.x,a.y+b.y);} complex operator-(complex a,complex b){return complex(a.x-b.x,a.y-b.y);} complex operator*(complex a,complex b){return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);} void swap(complex&a,complex&b){ complex c=a; a=b; b=c; } int rev[maxn],N; complex w[20][maxn]; void pre(int n){ int i,j,k; for(N=1,k=0;N<n;N<<=1)k++; for(i=0;i<N;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1)); for(i=2,k=0;i<=N;i<<=1){ for(j=0;j<i;j++)w[k][j]=complex(cos(j*M_PI/(i/2)),sin(j*M_PI/(i/2))); k++; } } void fft(complex*a,int on){ int i,j,k,f; complex t; for(i=0;i<N;i++){ if(i<rev[i])swap(a[i],a[rev[i]]); } f=0; for(i=2;i<=N;i<<=1){ for(j=0;j<N;j+=i){ for(k=0;k<i>>1;k++){ t=w[f][k]; t.y*=on; t=t*a[i/2+j+k]; a[i/2+j+k]=a[j+k]-t; a[j+k]=a[j+k]+t; } } f++; } if(on==-1){ for(i=0;i<N;i++)a[i].x/=N; } } char s[500010]; complex a[maxn],b[maxn]; int main(){ int n,i,j; bool flag; ll ans; scanf("%s",s); n=strlen(s); for(i=0;i<n;i++){ a[i]=s[i]=='0'; b[i]=s[n-1-i]=='1'; } pre(n<<1); fft(a,1); fft(b,1); for(i=0;i<N;i++)a[i]=a[i]*b[i]; fft(a,-1); ans=n*(ll)n; for(i=1;i<n;i++){ flag=1; for(j=i;j<n;j+=i){ if(fabs(a[n-1-j].x)>eps||fabs(a[n-1+j].x)>eps){ flag=0; break; } } if(flag)ans^=(n-i)*(ll)(n-i); } printf("%lld",ans); }