zoukankan      html  css  js  c++  java
  • BZOJ5372 PKUSC2018神仙的游戏(NTT)

      首先有一个想法,翻转串后直接卷积看有没有0匹配上1。但这是必要而不充分的因为在原串和翻转串中?不能同时取两个值。

      先有一些结论:

      如果s中长度为len的前缀是border,那么其存在|s|-len的循环节(最后一段不一定完整)。

      如果已知len不是s的循环节,那么显然len的因子也不是s的循环节。

      如果位置差为len的两个位置无法匹配,那么len不是s的循环节。

      于是可得:如果位置差为len的两个位置无法匹配,那么长度为|s|-(len的因子)的前缀不是border。

      可以发现其实问号出现冲突的原因就在于此,即某两个01的位置差为len,而问号在两者之间且与其中一个的位置差是len的因子。

      那么这是充分的,即只要不会被筛掉则一定是border。

      那么我们卷完后只要枚举长度去看他的倍数有没有被筛掉就可以了。由调和级数,复杂度O(nlogn)。

      LOJ过了,BZOJ上不出意外地T掉了。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define N 1050000
    #define P 998244353 
    #define inv3 332748118
    int n,t,s[N],a[N],b[N],f[N],r[N];
    long long ans;
    int ksm(int a,int k)
    {
        if (k==0) return 1;
        int tmp=ksm(a,k>>1);
        if (k&1) return 1ll*tmp*tmp%P*a%P;
        else return 1ll*tmp*tmp%P;
    }
    void DFT(int n,int *a,int p)
    {
        for (int i=0;i<n;i++) if (i<r[i]) swap(a[i],a[r[i]]);
        for (int i=2;i<=n;i<<=1)
        {
            int wn=ksm(p,(P-1)/i);
            for (int j=0;j<n;j+=i)
            {
                int w=1;
                for (int k=j;k<j+(i>>1);k++,w=1ll*w*wn%P)
                {
                    int x=a[k],y=1ll*w*a[k+(i>>1)]%P;
                    a[k]=(x+y)%P,a[k+(i>>1)]=(x-y+P)%P;
                }
            }
        }
    }
    void mul(int n)
    {
        DFT(n,a,3),DFT(n,b,3);
        for (int i=0;i<n;i++) a[i]=1ll*a[i]*b[i]%P;
        DFT(n,a,inv3);
        int inv=ksm(n,P-2);
        for (int i=0;i<n;i++) a[i]=1ll*a[i]*inv%P;
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj5372.in","r",stdin);
        freopen("bzoj5372.out","w",stdout);
        const char LL[]="%I64d";
    #else
        const char LL[]="%lld";
    #endif
        char c=getchar();
        while (c=='0'||c=='1'||c=='?')
        s[n++]=(c=='?'?-1:(c^48)),c=getchar();
        t=1;while (t<=(n<<1)) t<<=1;
        for (int i=0;i<t;i++) r[i]=(r[i>>1]>>1)|(i&1)*(t>>1);
        memset(a,0,sizeof(a));memset(b,0,sizeof(b));
        for (int i=0;i<n;i++) a[i]=(s[i]==1);
        for (int i=0;i<n;i++) b[i]=(s[n-i-1]==0);
        mul(t);
        for (int i=0;i<n;i++) f[n-i-1]+=(a[i]>0);
        memset(a,0,sizeof(a));memset(b,0,sizeof(b));
        for (int i=0;i<n;i++) a[i]=(s[i]==0);
        for (int i=0;i<n;i++) b[i]=(s[n-i-1]==1);
        mul(t);
        for (int i=0;i<n;i++) f[n-i-1]+=(a[i]>0);
        for (int i=1;i<n;i++)
        {
            ans^=1ll*(n-i)*(n-i);
            for (int j=i;j<=n;j+=i)
            if (f[j]) {ans^=1ll*(n-i)*(n-i);break;}
        }
        ans^=1ll*n*n;
        cout<<ans;
        return 0;
    }

      

  • 相关阅读:
    hibernate 数据处理
    oracle函数
    TCP聊天工具
    Hibernate批量处理数据、HQL连接查询
    Hibernate二级缓存配置
    Hibernate一对一关联映射配置
    Hibernate延迟加载
    Hibernate双向多对多关联
    06章 映射一对多双向关联关系、以及cascade、inverse属性
    映射对象标识符
  • 原文地址:https://www.cnblogs.com/Gloid/p/9449034.html
Copyright © 2011-2022 走看看