首页 > 其他 > 详细

LOJ6436 PKUSC2018 神仙的游戏

时间:2019-06-19 09:02:36      阅读:101      评论:0      收藏:0      [点我收藏+]

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匹配字符串 详情可见这里

可以设技术分享图片,技术分享图片

然后正常求卷积的话我们求出来是位置和 根据常见套路我们翻转一个多项式就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\n",getans());
    return 0;
}
View Code

 

LOJ6436 PKUSC2018 神仙的游戏

原文:https://www.cnblogs.com/hanyuweining/p/11049287.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!