zoukankan      html  css  js  c++  java
  • LOJ6436 PKUSC2018 神仙的游戏

    PKUSC2018除了主斗地都补完啦

    好大啊【糟糕的语言

    主斗地等什么时候空下来较长的时间再补吧。。。

    回到这个题

    当时听罗大讲并没有听明白...但是大概还是懂了的 就是我们可以通过找到所有01对位置差来筛掉所有不符合的border 具体证明放下面了

    首先我们介绍一点基本的border相关理论

    1.长度为x的border代表着 长度为x的前缀与长度为x的后缀相同

    2.长度为x的周期代表着 每隔x个字符一截 每一段都相同【除最后一段可能不够长

    3.长度为i的border对应着长度为n-i的周期

    那么对于一对01位置差为x 那么显然border不能让他们重合 所以对于y|x 一定不存在长度为n-y的border

    这个简单画画就可以理解

    有了所有的位置差 我们可以筛一下就行了 这就是调和级数啦 所以我们问题解决了一半

    接下来我们就要求所有的01位置差

    枚举肯定是不行的 但是可以过O(n^2)的67部分分[huaji]

    然后我们需要找更好的办法 这时你可以想到原来的FFT匹配字符串 详情可见这里

    可以设A(x)=sum [ch_i==0]x^i,B(x)=sum [ch_i == 1]x^i

    然后正常求卷积的话我们求出来是位置和 根据常见套路我们翻转一个多项式就ok啦

    具体写法什么的看看代码比较吼w 这个题也不长 挺好的

    //Love and Freedom.
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #define ll long long
    #define inf 20021225
    #define N 500010
    #define mdn 998244353
    #define G 3
    using namespace std;
    
    int ksm(int bs,int mi)
    {
        int ans=1;
        while(mi)
        {
            if(mi&1)    ans=(ll)ans*bs%mdn;
            bs=(ll)bs*bs%mdn; mi>>=1; 
        }
        return ans;
    }
    int r[N<<2],inv;
    int pre(int n)
    {
        int l=0,lim=1;
        while(lim<n)    lim<<=1,l++;
        for(int i=0;i<lim;i++)    r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
        inv=ksm(lim,mdn-2); return lim;
    }
    void ntt(int *a,int lim,int f)
    {
        for(int i=0;i<lim;i++)    if(r[i]>i)
            swap(a[r[i]],a[i]);
        for(int k=2,mid=1;k<=lim;k<<=1,mid<<=1)
        {
            int Wn=ksm(G,(mdn-1)/k);
            if(f)    Wn=ksm(Wn,mdn-2);
            for(int i=0,w=1;i<lim;i+=k,w=1)
                for(int j=0;j<mid;j++,w=(ll)w*Wn%mdn)
                {
                    int x=a[i+j],y=(ll)w*a[i+mid+j]%mdn;
                    a[i+j]=(x+y)%mdn; a[i+j+mid]=(mdn+x-y)%mdn;
                }
        }
        if(f)    for(int i=0;i<lim;i++)    a[i]=(ll)a[i]*inv%mdn;
    }
    bool bor[N]; int a[N<<2],b[N<<2],n; char ch[N];
    void sieve()
    {
        for(int i=1;i<n;i++)    for(int j=i;j<n;j+=i)
            if(a[n-j-1]|a[n+j-1]){bor[n-i]=0;break;}
    }
    ll getans()
    {
        ll ans=0;
        for(int i=1;i<=n;i++)    ans^=((ll)bor[i]*i*i);
        return ans;
    }
    int main()
    {
        memset(bor,1,sizeof(bor));
        scanf("%s",ch); n=strlen(ch);
        for(int i=0;i<n;i++)    a[i]=(ch[i]=='0'),b[i]=(ch[n-i-1]=='1');
        int lim=pre(n<<1);
        ntt(a,lim,0); ntt(b,lim,0);
        for(int i=0;i<lim;i++)    a[i]=(ll)a[i]*b[i]%mdn;
        ntt(a,lim,1); sieve();
        printf("%lld
    ",getans());
        return 0;
    }
    View Code
  • 相关阅读:
    Jenkins Pipeline Script from SCM应用
    Jenkins获取所有job
    Jenkins pipeline使用git共享库(ShareLibrary)
    Jenkins获取用户所属组
    PowerShell函数当做变量传递给另一个函数
    Jenkins input获取提交人
    Groovy Map排序
    Jenkins Pipeline使用File parameter
    Jenkins Active Parameters之Groovy Script(获取具有管理员权限的组+组成员)
    Android中C/C++的日志打印
  • 原文地址:https://www.cnblogs.com/hanyuweining/p/11049287.html
Copyright © 2011-2022 走看看