• bzoj 5372: [Pkusc2018]神仙的游戏


    Description

    小D和小H是两位神仙。他们经常在一起玩神仙才会玩的一些游戏,比如“口算一个4位数是不是完全平方数”。
    今天他们发现了一种新的游戏:首先称s长度为len的前缀成为border当且仅当
    s[1…len]=s[|s|-len+1…|s|]。
    给出一个由01?组成的字符串s,将s中的问号用变成01替换,对每个len口算是否存在替换问号的方案使得s长度为len的前缀成为border,
    把这个结果记做f(len)∈{0,1}。f(len)=1如果s长度为len的前缀能够成为border,否则f(len)=0
    由于小D和小H是神仙,所以他们计算的s的长度很长,因此把计算的结果一一比对会花费很长的时间。为了方便比对,他们规定了一个校验值:
    (f(1)12)xor(f(2)22)xor(f(3)32)xor…xor(f(n)n2)
    来校验他们的答案是否相同。xor表示按位异或。
    但是不巧,在某一次游戏中,他们口算出的校验值并不一样,他们希望你帮助他们来计算一个正确的校验值。
    当然,他们不强迫你口算,可以编程解决。

    Solution

    首先假设 (border=len) , 那么相当于是把串 (s[1...len]) 向右平移 (n-len) , 然后这个串和平移后的相等.
    也就是说存在一个长度为 (x) 的循环节 , 那么就存在 (border=n-x) , 所以判断是否存在循环节就行了.
    对于一对 (i,j) , (s[i]!=s[j]!='?') , 那么就不存在长度为 (|i-j|) 的循环节 , 自然也不存在 (|i-j|) 约数的循环节.
    所以我们把不合法的判掉 , 剩下的就是循环节了 , 距离为 (i-j) 的所有字符对一起考虑 , 只需要把 (j) 变成 (n-j) 做一边 (FFT) ,通过位置 (i-j+n) 就可以判断是否存在长度为 (i-j) 的循环节了.

    #include<bits/stdc++.h>
    using namespace std;
    template<class T>void gi(T &x){
    	int f;char c;
    	for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
    	for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
    }
    typedef complex<double> dob;
    const int N=2e6+10;const double pi=acos(-1.0);
    int n,m,R[N],L=0,d[N];char s[N];
    inline void FFT(dob *A,int o){
    	for(int i=0;i<n;i++)if(i<R[i])swap(A[i],A[R[i]]);
    	for(int i=1;i<n;i<<=1){
    		dob wn(cos(pi/i),sin(pi*o/i)),x,y;
    		for(int j=0;j<n;j+=i<<1){
    			dob w(1,0);
    			for(int k=0;k<i;k++,w=w*wn){
    				x=A[j+k],y=w*A[j+k+i];
    				A[j+k]=x+y,A[j+k+i]=x-y;
    			}
    		}
    	}
    }
    dob A[N],B[N];
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      scanf("%s",s+1),m=strlen(s+1);
      for(n=1;n<=(m<<1);n<<=1)L++;
      for(int i=0;i<n;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
      for(int i=1;i<=m;i++)A[m-i]=(s[i]=='1'),B[i]=(s[i]=='0');
      FFT(A,1),FFT(B,1);
      for(int i=0;i<=n;i++)A[i]*=B[i];
      FFT(A,-1);
      for(int i=m+1;i<n;i++)d[i-m]=(int)(A[i].real()/n+0.5)|(int)(A[2*m-i].real()/n+0.5);
      for(int i=m;i>=1;i--)
    	  if(!d[i])for(int j=i;j<=m;j+=i)if(d[j]){d[i]=1;break;}
      long long ans=0;
      for(int i=1;i<=m;i++)if(!d[m-i])ans^=1ll*i*i;
      cout<<ans;
      return 0;
    }
    
    
  • 相关阅读:
    Vue项目中全局过滤器的使用(格式化时间)
    vue-photo-preview 图片放大功能
    mongoimport导入json文件
    node后台,MongoDB作为数据库,vue前端获取数据并渲染
    JeasyUI,导出Excel
    EasyUI的textbox的disable ,readonly 用法
    EasyUI 中 Combobox里的onChange和onSelect事件的区别
    NullReferenceException 的可恨之处
    最新国家行政区划代码,来自国家统计局2018年底最新数据
    把旧系统迁移到.Net Core 2.0 日记 (20) --使用MiniProfiler for .NET
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9306000.html
Copyright © 2020-2023  润新知