「PKUSC2018」神仙的游戏 [FFT]

「PKUSC2018」神仙的游戏

Tags: FFT KMP Border


「PKUSC2018」神仙的游戏

题意

对于一个长度为n的字符串。

fi={10if(s[1...i]=s[ni+1...n])if(s[1...i]s[ni+1...n]) f i = { 1 i f ( s [ 1... i ] = s [ n − i + 1... n ] ) 0 i f ( s [ 1... i ] ≠ s [ n − i + 1... n ] )

要求 (f1i2)xor(f222)...xor(fnn2) ( f 1 ∗ i 2 ) x o r ( f 2 ∗ 2 2 ) . . . x o r ( f n ∗ n 2 )

分析


border
很好这个(对我来说)新奇的东西把我这种什么都不会的苣蒻淘汰下去了。
这个东西来自KMP算法。暂且不考虑和KMP算法的联系,单单来看border的性质有什么呢。
以下内容全部来自这篇题解

定理内容:
s[1,i]=s[ni+1,n] s [ 1 , i ] = s [ n − i + 1 , n ] 其实就是对于s有长度为(n-i)的循环节 (最后一个循环节不需要完整)

推论1
对于任意的i满足 si=sni+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对。

a[i]={1,0,if s[i]=0 if s[i] 0b[ni]={1,0,if s[i]=1if s[i] 1 a [ i ] = { 1 , if s[i]=0  0 , if s[i] ≠  0 b [ n − i ] = { 1 , if s[i]=1 0 , if s[i] ≠  1

卷积后的结果记作c,是否存在长度为d的border记作f[d]那么有
f[n]={1,0,if n|if[i]=0 and c[n-i]=0 and c[n+i]=0other f [ n ] = { 1 , if  ∑ n | i f [ i ] = 0  and c[n-i]=0 and c[n+i]=0 0 , other


以下是AC了之后的扯淡。
知道这个东西的性质之后其实还是蛮水的,但是不知道的话当场推好像还是稍微有点难度啊qwq?
然后就是写了最后一挡之后的确很好用fft优化,但是也很容易因为各种原因挂掉诶?(挂了一次)

code

#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;
}

你可能感兴趣的:(KMP,FFT,Border)