MTT:任意模数NTT

MTT:任意模数NTT

概述

有时我们用FFT处理的数据很大,而模数可以分解为\(a\cdot 2^k+1\)的形式。次数用FFT精度不够,用NTT又找不到足够大的模数,于是MTT就应运而生了。

MTT没有模数的限制,比NTT更加自由,应用广泛,可以用于任意模数或很大的数。

MTT

MTT是基于NTT的,其思想很简单,就是做多次NTT,每次使用不同的素数,然后使用CRT合并解,在合并的过程中模最终模数,或是对于无模数的情况使用高精度。

做NTT的次数取决于最大可能答案的大小,所用的所有素数之积必须大于答案

实现

此处以取三个素数为例
我们可以做三次NTT,相邻次之间改变素数,但这样常数太大,于是我们常常选择封装(适合于模数不太多的情况)。
我们定义一个结构体node,有三个成员a,b,c,分别代表三个模数下的值,同时,我们定义模数的结构体与之一一对应。

struct node{
    LL a,b,c;
    node(){
        a=b=c=0;
    }
    node(LL x){
        a=b=c=x;
    }
    node(LL x,LL y,LL z){
        a=x;
        b=y;
        c=z;
    }
}MOD=node(167772161,469762049,998244353),BASE=node(3),INV=node(116878283,426037461,929031873);

我们还要定义关于此结构体的运算,其中成员之间互不影响,只和操作对象里对应的成员产生运算

inline node operator+(node x,node y){
    return node(x.a+y.a,x.b+y.b,x.c+y.c);
}
inline node operator-(node x,node y){
    return node(x.a-y.a,x.b-y.b,x.c-y.c);
}
inline node operator*(node x,node y){
    return node(x.a*y.a%MOD.a,x.b*y.b%MOD.b,x.c*y.c%MOD.c);
}
inline node operator%(node x,node y){
    return node(x.a%y.a,x.b%y.b,x.c%y.c);
}
inline node operator/(node x,node y){
    return node(x.a/y.a,x.b/y.b,x.c/y.c);
}
inline node operator-(node x,LL y){
    return node(x.a-y,x.b-y,x.c-y);
}
inline node operator*(node x,LL y){
    return node(x.a*y,x.b*y,x.c*y);
}
inline node operator/(node x,LL y){
    return node(x.a/y,x.b/y,x.c/y);
}
inline node operator%(node x,LL y){
    return node(x.a%y,x.b%y,x.c%y);
}

例题

猜你喜欢

转载自www.cnblogs.com/guoshaoyang/p/11296140.html