• [PKUSC2018]神仙的游戏 题解


    [PKUSC2018]神仙的游戏 题解

    Problem

    ​ 小D和小H发现了一种新的游戏。

    ​ 给出一个由0/1/?组成的字符串 (s) ,将 (s) 中的问号用0/1替换,对每个 (l) 口算是否存在替换问号的方案使得 (s) 长度为 (l) 的前缀成为border,把这个结果记做 (f(l)=0/1)

    请计算 ((f(1) imes 1^2) otimes (f(2) imes 2^2) otimes cdots otimes (f(n) imes n^2))

    (|s| leq 5 imes 10^5)

    Solution

    对于一个长度为 (len) 的border,必定会有 (s_{i}=s_{n-len+i})

    我们可以得到一个这样的性质:若任取 (i equiv j (mod x)) ,都有 (s_i=s_j) ,则 (n-x) 是一个border。

    所以,倘若 (i equiv j (mod x))(s_i eq s_j) ,则 (n-x) 必定不是一个border。即只要知道有一对01的差是 (d) ,就一定会有对于一个 ((n-len)|d)(len) 都不是一个border。

    所以我们只要求出两两01的差,就能判断border,而这个只要FFT即可。

    Code

    #include<bits/stdc++.h>
    #define DB double
    #define LL long long
    using namespace std;
    
    const DB Pi=acos(-1);
    
    LL n,Ans;
    char s[500005];
    int vis[500005],rev[2000005];
    
    struct Complex{
    
        DB x,y;
    
        inline Complex operator + (const Complex &A)const{
            return (Complex){x+A.x,y+A.y};
        }
    
        inline Complex operator - (const Complex &A)const{
            return (Complex){x-A.x,y-A.y};
        }
    
        inline Complex operator * (const Complex &A)const{
            return (Complex){x*A.x-y*A.y,x*A.y+y*A.x};
        }
    
    }F[2000005],G[2000005];
    
    void FFT(Complex *F,int Lim,int op){
        for(register int i=0;i<Lim;++i){
            if(i<rev[i])
                swap(F[i],F[rev[i]]);
        }
        for(register int mid=1;mid<Lim;mid<<=1){
            int R=mid<<1;
            Complex rt=(Complex){cos(Pi/mid),op*sin(Pi/mid)};
            for(register int j=0;j<Lim;j+=R){
                Complex w=(Complex){1,0};
                for(register int k=0;k<mid;++k){
                    Complex x=F[j|k],y=w*F[j|k|mid];
                    F[j|k|mid]=x-y;
                    F[j|k]=x+y;
                    w=w*rt;
                }
            }
        }
        if(op==-1){
            for(register int i=0;i<Lim;++i){
                F[i].x/=Lim;
                F[i].y/=Lim;
            }
        }
        return;
    }
    
    int main(){
        
        scanf("%s",s+1);n=strlen(s+1);
    
        int Lim=1,Len=-1;
        while(Lim<(n+1<<1))
            Lim<<=1,++Len;
        for(register int i=0;i<Lim;++i)
            rev[i]=(rev[i>>1]>>1)|((i&1)<<Len);
    
        for(register int i=0;i<n;++i)
            F[i].x=(s[i+1]=='0');
    
        for(register int i=0;i<n;++i)
            G[i].x=(s[n-i]=='1');
    
        FFT(F,Lim,+1);FFT(G,Lim,+1);
        for(register int i=0;i<Lim;++i)
            F[i]=F[i]*G[i];
        FFT(F,Lim,-1);
    
        for(register int i=1;i<(n<<1);++i)
            vis[abs(i-n+1)]+=(F[i].x+0.5);
    
        for(register int i=1;i<n;++i){
            int flag=1;
            for(register int j=1;i*j<=n;++j){
                if(vis[i*j]){
                    flag=0;
                    break;
                }
            }
            if(flag)
                Ans^=1LL*(n-i)*(n-i);
        }
    
        printf("%lld
    ",Ans^(1LL*n*n));
    
        return 0;
    }
    
  • 相关阅读:
    hdu 1669(二分+多重匹配)
    hdu 2389(最大匹配bfs版)
    hdu 3118(二进制枚举)
    计算机常用端口一览表
    自制EIGRP配置实验大全
    自制EIGRP配置实验大全
    《生成树选举口诀》【转载】
    CCNA基础知识摘录
    对eigrp默认网络的理解!
    对eigrp默认网络的理解!
  • 原文地址:https://www.cnblogs.com/zjy123456/p/13836474.html
Copyright © 2020-2023  润新知