loj 6436 PKUSC2018 神仙的游戏

传送门

好妙蛙

即串\(s\)长度为\(n\)首先考虑如果一个长度为\(len\)\(border\)存在,当且仅当对所有\(i\in[1,len],s[i]=s[n-len+i]\),也就是所有模\(n-len\)同余的所有位置上的字符要相同,如果存在一对(0,1),他们之间的下标之差为\(x\),则对于所有的\(y|x\),长度为\(n-y\)\(border\)不存在

所以暴力做法是枚举所有确定的(0,1)对,然后把所有得到的长度以及这些长度的因数全部标记,利用质因数分解统计答案可以做到\(O(nlogn)\)

现在考虑优化前面的枚举部分,搞两个生成函数\(A(x)=\sum_{i=0}^{n-1}[s_i=0]x^i,B(x)=\sum_{i=0}^{n-1}[s_{n-i-1}=1]x^i\),如果把他们\(FFT\)起来,得到的\(C(x)\)\(C_k=\sum_{j=0}^{k}A_jB_{k-j}=\sum_{j=0}^{k}[s_j=0][s_{n-k-1+j}=1]x^k\),这第\(k\)项的系数也就是下标之差为\(|n-k-1|\)的(0,1)对数量

然后就可以\(O(nlogn)\)加大常数完成此题

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
#define db double
#define il inline
#define re register
#define eps (1e-5)
  
using namespace std;
const int N=500000+10,M=1050000+10;
const db pi=acos(-1);
il int rd()
{
  int x=0,w=1;char ch=0;
  while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
  while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
  return x*w;
}
struct comp
{
  db r,i;
  comp(){r=i=0;}
  comp(db nr,db ni){r=nr,i=ni;}
  il comp operator + (const comp &bb) const {return comp(r+bb.r,i+bb.i);}
  il comp operator - (const comp &bb) const {return comp(r-bb.r,i-bb.i);}
  il comp operator * (const comp &bb) const {return comp(r*bb.r-i*bb.i,r*bb.i+i*bb.r);}
}a[M],b[M];
int n,m,nn,l,rdr[M];
il void fft(comp *a,int op)
{
  comp W,w,x,y;
  for(int i=0;i<nn;++i) if(i<rdr[i]) swap(a[i],a[rdr[i]]);
  for(int i=1;i<nn;i<<=1)
    {
      W=comp(cos(pi/i),op*sin(pi/i));
      for(int j=0;j<nn;j+=i<<1)
        {
          w=comp(1,0);
          for(int k=0;k<i;++k,w=w*W)
            {
              x=a[j+k],y=w*a[j+k+i];
              a[j+k]=x+y,a[j+k+i]=x-y;
            }
        }
    }
}
char cc[N];
bool no[N];
int prm[N],tt,pp[N];

int main()
{
  scanf("%s",cc);
  n=strlen(cc);
  m=n+n;
  for(nn=1;nn<=m;nn<<=1) ++l;
  for(int i=0;i<nn;++i) rdr[i]=(rdr[i>>1]>>1)|((i&1)<<(l-1));
  for(int i=0;i<n;++i) a[i].r=(cc[i]=='0'),b[i].r=(cc[n-i-1]=='1');
  fft(a,1),fft(b,1);
  for(int i=0;i<nn;++i) a[i]=a[i]*b[i];
  fft(a,-1);
  for(int i=0;i<n;++i) no[i]=(fabs(a[n-1-i].r)/nn>eps||fabs(a[n-1+i].r)/nn>eps);
  for(int i=2;i<=n;++i)
    {
      if(!pp[i]) pp[i]=i,prm[++tt]=i;
      for(int j=1;j<=tt&&i*prm[j]<=n;++j)
        {
          pp[i*prm[j]]=prm[j];
          if(i%prm[j]==0) break;
        }
    }
  for(int i=n-1;i>=1;--i)
    {
      int x=i;
      while(x>1) no[i/pp[x]]|=no[i],x/=pp[x];
    }
  LL ans=0;
  for(int i=1;i<=n;++i) ans^=1ll*(no[n-i]^1)*i*i;
  printf("%lld\n",ans);
  return 0;
}
posted @ 2018-12-07 09:31  ✡smy✡  阅读(112)  评论(0编辑  收藏  举报