【模板】任意模数NTT

题目描述:

luogu

题解:

用$fft$水过(什么$ntt$我不知道)。

众所周知,$fft$精度低,$ntt$处理范围小。

所以就有了任意模数ntt神奇$fft$!

意思是这样的。比如我要算$F*G$,我可以把这两个多项式各分成两个多项式,一个表示$F_x/M$,一个表示$F_x%M$($M$是自己设定的阈值)。

比如说$F=a*M+b,G=c*M+d$,那么$F*G=(a*M+b)*(c*M+d)=a*c*M^2+a*d*M+b*c*M+b*d$。

然后?就水过了啊……

顺便提一下,要开$long double$。

代码:

【模板】任意模数NTT
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 500050;
const long double Pi = acos(-1.0);
template<typename T>
inline void read(T&x)
{
    T f = 1,c = 0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x = f*c;
}
int n,m,MOD;
struct cp
{
    long double x,y;
    cp(){}
    cp(long double x,long double y):x(x),y(y){}
    cp operator + (const cp&a)const{return cp(x+a.x,y+a.y);}
    cp operator - (const cp&a)const{return cp(x-a.x,y-a.y);}
    cp operator * (const cp&a)const{return cp(x*a.x-y*a.y,x*a.y+y*a.x);}
};
int to[N],lim,L;
void init()
{
    lim = 1,L = 0;
    while(lim<=2*max(n,m))lim<<=1,L++;
    for(int i=1;i<lim;i++)
        to[i] = ((to[i>>1]>>1)|((i&1)<<(L-1)));
}
ll A[N],B[N],C[N];
void fft(cp*a,int len,int k)
{
    for(int i=0;i<len;i++)
        if(i<to[i])swap(a[i],a[to[i]]);
    for(int i=1;i<len;i<<=1)
    {
        cp w0(cos(Pi/i),k*sin(Pi/i));
        for(int j=0;j<len;j+=(i<<1))
        {
            cp w(1,0);
            for(int o=0;o<i;o++,w=w*w0)
            {
                cp w1 = a[j+o],w2 = a[j+o+i]*w;
                a[j+o] = w1+w2;
                a[j+o+i] = w1-w2;
            }
        }
    }
    if(k==-1)
        for(int i=0;i<len;i++)a[i].x/=len;
}
cp a[N],b[N],c[N],d[N],e[N],f[N],g[N],h[N];
void mtt()
{
    int M = 32768;
    for(int i=0;i<max(n,m);i++)
    {
        a[i].x = A[i]/M,b[i].x = A[i]%M;
        c[i].x = B[i]/M,d[i].x = B[i]%M;
    }
    fft(a,lim,1),fft(b,lim,1),fft(c,lim,1),fft(d,lim,1);
    for(int i=0;i<lim;i++)
    {
        e[i] = a[i]*c[i],f[i] = a[i]*d[i];
        g[i] = b[i]*c[i],h[i] = b[i]*d[i];
    }
    fft(e,lim,-1),fft(f,lim,-1),fft(g,lim,-1),fft(h,lim,-1);
    for(int i=0;i<lim;i++)
        C[i] = (((ll)(e[i].x+0.1))%MOD*M%MOD*M%MOD+((ll)(f[i].x+0.1))%MOD*M%MOD
                +((ll)(g[i].x+0.1))%MOD*M%MOD+((ll)(h[i].x+0.1))%MOD)%MOD;
}
int main()
{
    read(n),read(m),read(MOD);n++,m++;
    init();
    for(int i=0;i<n;i++)read(A[i]);
    for(int i=0;i<m;i++)read(B[i]);
    mtt();
    for(int i=0;i<n+m-1;i++)printf("%lld ",C[i]);
    puts("");
    return 0;
}
View Code

 

上一篇:P4245 【模板】任意模数NTT


下一篇:【模板】分治FFT