[LOJ6436]神仙的游戏

感觉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);
}

猜你喜欢

转载自www.cnblogs.com/jefflyy/p/9181932.html