zoukankan      html  css  js  c++  java
  • 【洛谷5466】[PKUSC2018] 神仙的游戏(FFT)

    点此看题面

    • 给定一个长度为(n)(01)串,其中有一些字符缺失了。
    • 对于每一个(i),问是否存在一种填法使得长度为(i)的前缀与长度为(i)的后缀相同。
    • (nle5 imes10^5)

    一年前曾开过这道题,当时有个脑瘫的想法,调了半天才发现问题,一怒之下就弃了。

    一年后又开了这道题,又先有了当时那个脑瘫的想法,结果再次想了半天才重新发现问题,看来一年来实力毫无长进。。。

    (border)的性质

    对于一个长度为(i)的前缀,如果它与长度为(i)的后缀相同,我们称其为一个(border)

    (border)有一个基本性质,就是长度为(i)的前缀是(border),充要于(n-i)是该字符串的一个周期

    这个性质的证明,只要自己画下图,分前缀和后缀重叠与不重叠两类讨论一下就行了。

    解题思路

    考虑如果(i)可能成为(border),就是要判断(n-i)是否可能成为周期。

    也就是说,不能存在两个(0,1),满足它们的下标之差是(n-i)的倍数。

    因此我们令(a_i)表示(s_i)是否为0(b_i)表示(s_{n-i+1})是否为1

    那么只要((a*b)[n-x+1] ot=0)((a*b)[n+x+1] ot=0),就说明存在两个(0,1)下标之差为(x),则周期(x)非法。

    然后再对于每一个可能的周期,去看一下它的倍数中是否有非法的,如果有那么它也非法了。

    代码:(O(nlogn))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 500000
    #define DB double
    using namespace std;
    int n,a[2*N+5],b[N+5],p[N+5];char s[N+5];
    namespace Poly//多项式乘法
    {
    	int P,L,R[N<<2];DB Pi=acos(-1);
    	struct node
    	{
    		DB x,y;I node(Con DB& a=0,Con DB& b=0):x(a),y(b){}
    		I node operator + (Con node& o) Con {return node(x+o.x,y+o.y);}
    		I node operator - (Con node& o) Con {return node(x-o.x,y-o.y);}
    		I node operator * (Con node& o) Con {return node(x*o.x-y*o.y,x*o.y+y*o.x);}
    	}A[N<<2],B[N<<2];
    	I void FFT(node* s,CI op)
    	{
    		RI i,j,k;node U,S,x,y;for(i=0;i^P;++i) i<R[i]&&(x=s[i],s[i]=s[R[i]],s[R[i]]=x,0);
    		for(i=1;i^P;i<<=1) for(U=node(cos(Pi/i),op*sin(Pi/i)),j=0;j^P;j+=i<<1)
    			for(S=1,k=0;k^i;++k,S=S*U) s[j+k]=(x=s[j+k])+(y=S*s[i+j+k]),s[i+j+k]=x-y;
    	}
    	I void Mul(int* a,int* b)//卷积
    	{
    		RI i;P=1,L=0;W(P<=(n<<1)) P<<=1,++L;for(i=0;i^P;++i) R[i]=(R[i>>1]>>1)|((i&1)<<L-1);
    		for(i=1;i<=n;++i) A[i]=a[i],B[i]=b[i];FFT(A,1),FFT(B,1);
    		for(i=0;i^P;++i) A[i]=A[i]*B[i];for(FFT(A,-1),i=1;i<=2*n;++i) a[i]=A[i].x/P+0.5;
    	}
    }
    int main()
    {
    	RI i,j;for(scanf("%s",s+1),n=strlen(s+1),i=1;i<=n;++i) a[i]=s[i]=='0',b[n-i+1]=s[i]=='1';//初始化
    	for(Poly::Mul(a,b),p[0]=1,i=n;i;--i)
    		for(p[i]=!a[n-i+1]&&!a[n+i+1],j=i<<1;p[i]&&j<=n;j+=i) p[i]&=p[j];//如果倍数中有非法的,它也非法了
    	long long t=0;for(i=1;i<=n;++i) p[n-i]&&(t^=1LL*i*i);return printf("%lld
    ",t),0;//i是border充要于n-i是周期
    }
    
  • 相关阅读:
    Visual studio之C# 调用系统软键盘(外部"osk.exe")
    Visual studio之C# 重新定义Messbox的显示窗口位置
    Visual studio之C#的一些常见问题
    C8051F340之USB简介
    CentOS 安装 Sun JDK
    配置Tomcat以指定的身份(非root)运行
    CentOS6 root 用户 vi/vim 无法开启高亮
    删除 Mac OS X 中“打开方式”里重复或无用的程序列表
    快速建立Linux c/c++编译环境
    Ubuntu 安装 Sun JDK
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu5466.html
Copyright © 2011-2022 走看看