感觉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
否则分出来的任意两组都相同,即是说$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);
}