zoukankan      html  css  js  c++  java
  • [题解] Luogu P4245 [模板]任意模数NTT

    三模NTT 不会。。。

    都0202年了,还有人写三模NTT啊。。。


    讲一个好写点的做法吧:

    首先取一个阀值(w),然后把多项式的每个系数写成(aw + c(c < w))的形式,换句话说把多项式(f(x))写成两个多项式相加的形式:

    [f(x) = wf_0(x) + f_1(x) ]

    这样在这道题中取(W = 2^{15})就可以避免爆long long了。

    乘起来的话就是

    [f cdot g = (w f_0 + f_1)(wg_0 + g_1) = (f_0 g_0)w^2 + (f_0g_1 + f_1g_0) w + f_1g_1 ]

    这样我们只要算(f_0g_0, (f_0g_1 + f_1g_0), f_1g_1)就好了,分别(FFT)算一下。(这玩意儿好像叫(MTT),妙~啊)

    这样要做(7)(FFT),好像可以做到(4)次,不会。

    感觉这样也跑的挺快的。

    (Code)

    #include <bits/stdc++.h>
    using namespace std;
    typedef long double db;
    typedef long long ll;
    const db PI=acos(-1.0);
    const int N=3e5+10;
    struct cpl{
    	db x,y;
    	cpl operator + (cpl k1)const{return (cpl){x+k1.x,y+k1.y};}
    	cpl operator - (cpl k1)const{return (cpl){x-k1.x,y-k1.y};}
    	cpl operator * (cpl k1)const{return (cpl){x*k1.x-y*k1.y,x*k1.y+y*k1.x};}
    };
    int rev[N];
    void fft(cpl *f,int n,int k1){
    	for (int i=0;i<n;i++)
    		if (rev[i]<i)swap(f[i],f[rev[i]]);
    	for (int len=2;len<=n;len<<=1){
    		cpl wn=(cpl){cos(2*PI/len),k1*sin(2*PI/len)};
    		for (int i=0;i<n;i+=len){
    			cpl w=(cpl){1,0};
    			for (int j=i;j<i+(len>>1);j++){
    				cpl tmp=w*f[j+(len>>1)];
    				f[j+(len>>1)]=f[j]-tmp;
    				f[j]=f[j]+tmp;
    				w=w*wn;
    			}
    		}
    	}
    }
    cpl f[2][N],g[2][N],ans[3][N];
    #define normal(x) (((ll)(x/limit+0.5)%mod+mod)%mod)
    void mtt(int *a,int n,int *b,int m,int mod){
    	int limit=1; while (limit<=n+m)limit<<=1;
    	for (int i=0;i<limit;i++) rev[i]=rev[i>>1]>>1|((i&1)?limit>>1:0);
    	for (int i=0;i<limit;i++){
    		f[0][i].x=a[i]>>15;f[1][i].x=a[i]&0x7fff;
    		g[0][i].x=b[i]>>15;g[1][i].x=b[i]&0x7fff;
    	}
    	fft(f[0],limit,1),fft(f[1],limit,1);
    	fft(g[0],limit,1),fft(g[1],limit,1);
    	for (int i=0;i<limit;i++){
    		ans[0][i]=f[0][i]*g[0][i];
    		ans[1][i]=f[0][i]*g[1][i]+f[1][i]*g[0][i];
    		ans[2][i]=f[1][i]*g[1][i];
    	}
    	fft(ans[0],limit,-1),fft(ans[1],limit,-1),fft(ans[2],limit,-1);
    	for (int i=0;i<=n+m;i++){
    		ll k1=(normal(ans[0][i].x)<<30ll)%mod;
    		ll k2=(normal(ans[1][i].x)<<15ll)%mod;
    		ll k3=normal(ans[2][i].x)%mod;
    		printf("%d ",((k1+k2)%mod+k3)%mod);
    	}
    }
    int n,m,a[N],b[N],mod;
    int main(){
    	scanf("%d%d%d",&n,&m,&mod);
    	for (int i=0;i<=n;i++)scanf("%d",&a[i]);
    	for (int i=0;i<=m;i++)scanf("%d",&b[i]);
    	mtt(a,n,b,m,mod);
    	return 0;
    }
    
  • 相关阅读:
    KEIL5.25生成.bin文件步骤
    【转】树莓派网线直连笔记本电脑
    由编译器指定数组长度带来的一个问题
    【转】C/C++位域结构深入解析
    【转】大小端存储模式精解
    【转】树莓派入门之装系统
    【转】树莓派Raspberry Pi
    stm32的双向io口
    小记之while循环条件的操作位置
    【转】浮点数在计算机中存储方式
  • 原文地址:https://www.cnblogs.com/wxq1229/p/12235793.html
Copyright © 2011-2022 走看看