【loj6436】【pkusc2018】神仙的游戏

Portal --> pkuscD2T2(loj6436)

Solution

  个人觉得是道很好的法法塔题qwq

  一开始的时候想偏了想到了另一种法法塔处理字符串匹配之类的奇怪技巧(万径人踪灭qwq了解一下),然后非常天真的想把问号拿出来单独处理一波然后越走越远。。。

  好吧正解其实是(感觉貌似还是想的有点绕?应该有更加简便的思维方式不过qwq不管了qwq)

  因为有一个问号所以其实挺难直接得到哪些长度能够匹配,那不妨换个思路把所有肯定不能匹配的长度去掉那剩下的就是答案了

  肯定不能匹配的长度显然就是\(0\)\(1\)对上了,假设我们现在知道位置\(x\)有一个\(0\),位置\(y\)有一个\(1\),那么考虑当匹配长度\(k\)满足什么条件的时候这两个位置是对上的,那么满足这样条件的\(k\)显然就是可以去掉的了,那么可以得到(假设字符串从\(0\)开始,\(x<y\) ,记\(y-x=len\),字符串总长度为\(n\)):
\[ x=y-(n-k) \]
  化一下就是
\[ k=n-len \]
​  除此之外,这个匹配的话其实就是\(kmp\)那一套的感觉,因此用类似\(kmp\)\(next\)数组那样的想法(额其实也不是吧不知道怎么说就是各种推来推去有点像的感觉qwq)去推一下这个串会发现这样一个性质:记两个匹配串的开头位置的差为\(K\),如果存在一对下标差为\(len\)\(01\),那么满足\(K|len\)的长度都是无法匹配的

  具体一点就是这样

  第一个蓝点和红点的下标差是\(2K\)但是会影响到开头位置差为\(K\)的匹配

  所以得知了\(01\)对的下标差之后我们再枚举一下倍数筛一下就可以了

  

  至于\(01\)对的下标差,我们把\(x-y\)转成\(x+(n-1-y)\),这样的话就可以用法法塔来做了(注意\(s\)是从\(0\)开始的),考虑这样两个函数
\[ \begin{aligned} g(x)&=\sum [s[n-1-i]==0]x^i\\ f(x)&=\sum [s[i]==1]x^i\\ \end{aligned} \]
  我们把指数看成上面的\(x\)\(n-1-y\)然后直接这两个多项式乘一下,结果为\(h(x)\)

  那么对于\(h(x)\)中指数小于\(n\)的部分,表示的是\(x>y\)的情况(因为这部分的指数\(-(n-1)\)得到的是负数),取反一下就可以得到下标差了,大于等于\(n\)的部分直接减就好了

  最后枚举倍数筛一波然后输出就好了,注意这里的是首位的下标差所以\(i\)对应的长度应该是\(n-i\)

​   

  代码大概长这个样子(然而貌似用fft会更快但我也不知道为啥就写了ntt不管了qwq)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int MAXN=5*(1e5)+10,MOD=998244353,G=3;
int ksm(int x,int y);
namespace NTT{/*{{{*/
    int A[MAXN*4],B[MAXN*4],W[MAXN*4][2],rev[MAXN*4];
    int invg,len,invlen;
    void init(){
        invg=ksm(G,MOD-2);
        for (int i=0;i<=20;++i){
            W[1<<i][0]=ksm(G,(MOD-1)/(1<<i));
            W[1<<i][1]=ksm(invg,(MOD-1)/(1<<i));
        }
    }
    void prework(int *a,int *b,int n,int m){
        for (int i=0;i<len;++i) A[i]=B[i]=0;
        int bit=0;
        for (len=1;len<n+m;len<<=1,++bit);
        rev[0]=0;
        for (int i=1;i<len;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
        for (int i=0;i<=n;++i) A[i]=a[i];
        for (int i=0;i<=m;++i) B[i]=b[i];
        invlen=ksm(len,MOD-2);
    }
    void ntt(int *a,int op){
        int w,w_n,t,u;
        for (int i=0;i<len;++i) 
            if (rev[i]>i) swap(a[i],a[rev[i]]);
        for (int step=2;step<=len;step<<=1){
            w_n=op==1?W[step][0]:W[step][1];
            for (int st=0;st<len;st+=step){
                w=1;
                for (int i=0;i<(step>>1);++i){
                    t=1LL*a[st+i+(step>>1)]*w%MOD;
                    u=a[st+i];
                    a[st+i]=(1LL*u+t)%MOD;
                    a[st+i+(step>>1)]=(1LL*u-t+MOD)%MOD;
                    w=1LL*w*w_n%MOD;
                }
            }
        }
        if (op==1) return;
        for (int i=0;i<len;++i) a[i]=1LL*a[i]*invlen%MOD;
    }
    void Ntt(int *a,int *b,int n,int m){
        prework(a,b,n,m);
        ntt(A,1);
        ntt(B,1);
        for (int i=0;i<len;++i) A[i]=1LL*A[i]*B[i]%MOD;
        ntt(A,-1);
    }
    void debug(int *a,int n){
        prework(a,a,n,n);
        ntt(a,1);
        ntt(a,-1);
    }
}/*}}}*/
char s[MAXN];
int ori1[MAXN],ori0[MAXN],res[MAXN*2];
int out[MAXN];
ll ans;
int n,m,lens;
void prework();

int main(){
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
#endif
    scanf("%s",s);
    n=strlen(s);
    NTT::init();
    prework();
    NTT::Ntt(ori1,ori0,n,n);
    for (int i=0;i<=n*2;++i) res[i]=NTT::A[i];
    for (int i=0;i<n;++i) out[n-1-i]|=res[i];
    for (int i=n;i<2*n-1;++i) out[i-(n-1)]|=res[i];
    for (int i=1;i<=n;++i)
        for (int j=i;j<=n&&!out[i];j+=i)
            if (out[j]) out[i]=1;
    ans=0;
    for (int i=1;i<=n;++i)
        if (!out[n-i]) ans^=1LL*i*i;
    printf("%lld\n",ans);
}

int ksm(int x,int y){
    int ret=1,base=x;
    for (;y;y>>=1,base=1LL*base*base%MOD)
        if (y&1) ret=1LL*ret*base%MOD;
    return ret;
}

void prework(){
    for (int i=0;i<n;++i)
        ori1[i]=s[i]=='1',ori0[i]=s[i]=='0';
    reverse(ori0,ori0+n);
}

猜你喜欢

转载自www.cnblogs.com/yoyoball/p/9184779.html