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;
}

  

猜你喜欢

转载自www.cnblogs.com/Gloid/p/9449034.html