zoukankan      html  css  js  c++  java
  • BZOJ 3992 [SDOI2015]序列统计

    题解:求m的原根,把乘法转化成加法,然后用NTT加速动态规划
    听说这是循环卷积???并不会啊,留个坑。

    NTT连板子都不熟

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn=1000009;
    typedef long long Lint;
    const Lint mm2=1004535809;
    
    int n,m,fin,mm;
    
    Lint g;
    int ref[maxn];
    void Getg(){
    	for(g=2;g<mm;++g){
    		Lint tmp=1;
    		int fla=1;
    		for(int i=1;i<mm-1;++i){
    			tmp=tmp*g%mm;
    			if(tmp==1){
    				fla=0;break;
    			}
    		}
    		if(fla)break;
    	}
    	Lint tmp=1;ref[1]=0;
    	for(int i=1;i<mm-1;++i){
    		tmp=tmp*g%mm;
    		ref[tmp]=i;
    	}
    }
    
    Lint Ksm(Lint a,Lint p){
    	Lint ret=1;
    	for(;p;p>>=1,a=a*a%mm2){
    		if(p&1)ret=ret*a%mm2;
    	}
    	return ret;
    }
    
    Lint a[maxn];
    Lint b[maxn];
    Lint ret[maxn];
    
    int l,rev[maxn];
    
    void NTT(Lint *a,int f,int n){
    	for(int i=0;i<n;++i)if(i<rev[i])swap(a[i],a[rev[i]]);
    	
    	for(int i=1;i<n;i<<=1){
    		int p=i+i;
    		Lint wn=Ksm(3,mm2/p);
    		if(f==-1)wn=Ksm(wn,mm2-2);
    		for(int j=0;j<n;j+=p){
    			Lint w=1;
    			for(int k=0;k<i;++k,w=w*wn%mm2){
    				Lint x=a[j+k],y=a[j+k+i]*w%mm2;
    				a[j+k]=(x+y)%mm2;a[j+k+i]=(x-y+mm2)%mm2;
    			}
    		}
    	}
    	if(f==-1){
    		Lint inv=Ksm(n,mm2-2);
    		for(int i=0;i<n;++i)a[i]=a[i]*inv%mm2;
    	}
    }
    
    void Getans(int p){
    	m=mm+mm-4;
    	int n;
    	for(n=1;n<=m;n<<=1)l++;
    	for(int i=0;i<n;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
    	ret[0]=1;
    	for(;p;p>>=1){
    		if(p&1){
    			for(int i=0;i<n;++i)b[i]=a[i];
    			NTT(ret,1,n);NTT(b,1,n);
    			for(int i=0;i<n;++i)ret[i]=ret[i]*b[i]%mm2;
    			NTT(ret,-1,n);
    			for(int i=mm-1;i<n;++i){
    				ret[i%(mm-1)]+=ret[i];ret[i]=0;
    			}
    			for(int i=0;i<mm-1;++i)ret[i]%=mm2;
    		}
    		for(int i=0;i<n;++i)b[i]=a[i];
    		NTT(a,1,n);NTT(b,1,n);
    		for(int i=0;i<n;++i)a[i]=a[i]*b[i]%mm2;
    		NTT(a,-1,n);
    		for(int i=mm-1;i<n;++i){
    			a[i%(mm-1)]+=a[i];a[i]=0;
    		}
    		for(int i=0;i<mm-1;++i)a[i]%=mm2;
    //		for(int i=0;i<n;++i)cout<<a[i]<<' ';
    //		cout<<endl;
    	}
    }
    
    int main(){
    	scanf("%d%d%d%d",&n,&mm,&fin,&m);
    	Getg();
    	while(m--){
    		int x;scanf("%d",&x);
    		if(x!=0)a[ref[x]]++;
    	}
    	Getans(n);
    	printf("%lld
    ",ret[ref[fin]]%mm2);
    	return 0;
    }
    

      

    自己还是太辣鸡了
  • 相关阅读:
    趣味网站、趣味应用
    趣味网站、趣味应用
    论文写作的句型
    Python Tricks(二十一)—— 排列组合的计算
    Python Tricks(二十一)—— 排列组合的计算
    辨异 —— 有两人生日在同一天、只有两人生日在同一天
    辨异 —— 有两人生日在同一天、只有两人生日在同一天
    品味电影
    品味电影
    HDU 4414 Finding crosses (DFS + BFS)
  • 原文地址:https://www.cnblogs.com/zzyer/p/8456616.html
Copyright © 2011-2022 走看看