zoukankan      html  css  js  c++  java
  • [LOJ6436][PKUSC2018]神仙的游戏

    loj

    description

    给你一个只有01?的字符串,问你是否存在一种把?改成01的方案使串存在一个长度为(1-n)(border)(nle5 imes10^5)

    sol

    这种题都不会我还是太菜了。
    有一档部分分是“01的个数不超过(5000)”。这个其实对正解的提示是蛮大的。
    有一个显然的结论:存在一个长度为(len)(border)当且仅当对于(forall iin[1,len])(s[i]=s[n-len+i])。(感谢热心网友找出这里的一个错误)
    或者这样说,把所有位置在模(n-len)意义下分组,同一组里的01要全部相同。
    那么,如果存在一组01他们的下标之差为(x),那么所有(y|x)(n-y)都不可能成为(border)
    这样(67)分就可以写一个(5000^2)枚举01对统计,然后每次扫一遍倍数(O(nlog n))计算答案。

    考虑正解。现在的复杂度瓶颈在于枚举01对。
    搞两个生成函数(A(x))(B(x))(A(x)=sum_{i=0}^{n-1}[s_i==0]x^i)(B(x)=sum_{i=0}^{n-1}[s_i==1]x^i)
    我们知道,多项式卷积计算的是所有下标之和为一定值的乘积之和,也就是(C_i=sum_{j+k=i}A_jB_k)。现在我们要统计的是差为定值的。
    把一个多项式(reverse)过来不就好了么。形式化地,令(A(x)=x^{n-1}A(frac 1x)),然后计算(C(x)=A(x)B(x))得到的第(i)次项系数就是满足“1的下标减0的下标等于(i-n)”的01对数。
    复杂度(O(nlog n))

    code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int gi(){
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    const int N = 3e6+5;
    const int mod = 998244353;
    int n,len,a[N],b[N],rev[N],l,og[N];
    char s[N];
    int fastpow(int a,int b){
    	int res=1;
    	while (b) {if (b&1) res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}
    	return res;
    }
    void ntt(int *P,int opt){
    	for (int i=0;i<len;++i) if (i<rev[i]) swap(P[i],P[rev[i]]);
    	for (int i=1;i<len;i<<=1){
    		int W=fastpow(3,(mod-1)/(i<<1));
    		if (opt==-1) W=fastpow(W,mod-2);
    		og[0]=1;
    		for (int j=1;j<i;++j) og[j]=1ll*og[j-1]*W%mod;
    		for (int p=i<<1,j=0;j<len;j+=p)
    			for (int k=0;k<i;++k){
    				int x=P[j+k],y=1ll*og[k]*P[j+k+i]%mod;
    				P[j+k]=(x+y)%mod;P[j+k+i]=(x-y+mod)%mod;
    			}
    	}
    	if (opt==-1) for (int i=0,Inv=fastpow(len,mod-2);i<len;++i) P[i]=1ll*P[i]*Inv%mod;
    }
    int main(){
    	scanf("%s",s);n=strlen(s);
    	for (len=1;len<=(n<<1);len<<=1) ++l;--l;
    	for (int i=0;i<len;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<l);
    	for (int i=0;i<n;++i) a[i]=s[i]=='0',b[i]=s[n-i-1]=='1';
    	ntt(a,1);ntt(b,1);
    	for (int i=0;i<len;++i) a[i]=1ll*a[i]*b[i]%mod;
    	ntt(a,-1);
    	long long ans=1ll*n*n;
    	for (int i=1;i<n;++i){
    		int fg=1;
    		for (int j=i;j<n;j+=i) if (a[n-j-1]|a[n+j-1]) {fg=0;break;}
    		if (fg) ans^=1ll*(n-i)*(n-i);
    	}
    	printf("%lld
    ",ans);return 0;
    }
    
  • 相关阅读:
    eclipse插件
    01 vue入门
    jrebel
    html5,css3炫酷实例-元素
    css文字实例锦集
    海外短信故障已经恢复
    证实海外(含港澳台)短信业务故障
    预计维护时间将延长
    黑龙江地区电信运营商业务中断
    正在进行计划中的停机维护
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9141717.html
Copyright © 2011-2022 走看看