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);
}
然后套用NTT的板子,最后用CRT合并。
假设这一位的答案是\(x\),三个模数分别为\(A,B,C\),那么:
\]
先把前两个合并:
\]
于是求出了\(k_1\),也就求出了\(x\equiv x_1+k_1A\pmod{AB}\),记\(x_4=x_1+k_1A\)
\]
因为\(x<ABC\),所以
\]
LL CRT(node x){
LL mod1=MOD.a,mod2=MOD.b,mod3=MOD.c,mod_1_2=mod1*mod2;
LL inv_1=inv(mod1,mod2),inv_2=inv(mod1*mod2%mod3,mod3);
LL A=x.a,B=x.b,C=x.c;
LL x4=(B-A+mod2)%mod2*inv_1%mod2*mod1+A;
return ((C-x4%mod3+mod3)%mod3*inv_2%mod3*(mod_1_2%Last_Mod)+Last_Mod+x4)%Last_Mod;
}
于是我们就能写出完整代码了。
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF=1e9+7,MAXN=3e6+10/*Min:2^20+10*/;
void exgcd(LL a,LL b,LL &x,LL &y){
if(!b){
x=1;
y=0;
return;
}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
inline LL inv(LL x,LL p){
LL a,b;
exgcd(x,p,a,b);
return (a%p+p)%p;
}
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);
}
LL Last_Mod;
LL CRT(node x){
LL mod1=MOD.a,mod2=MOD.b,mod3=MOD.c,mod_1_2=mod1*mod2;
LL inv_1=inv(mod1,mod2),inv_2=inv(mod1*mod2%mod3,mod3);
LL A=x.a,B=x.b,C=x.c;
LL x4=(B-A+mod2)%mod2*inv_1%mod2*mod1+A;
return ((C-x4%mod3+mod3)%mod3*inv_2%mod3*(mod_1_2%Last_Mod)+Last_Mod+x4)%Last_Mod;
}
inline LL fpm_(LL base,LL p,LL mod){
LL ret=1;
while(p){
if(p&1)
ret=ret*base%mod;
base=base*base%mod;
p>>=1;
}
return ret%mod;
}
inline node fpm(LL base,node p){
return node(fpm_(base,p.a,MOD.a),fpm_(base,p.b,MOD.b),fpm_(base,p.c,MOD.c));
}
int N,M,lim=1,lg,rev[MAXN];
node Wn[MAXN];
inline void NTT(node *a,int type){
for(int i=0;i<lim;i++)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(int mid=1;mid<lim;mid<<=1){
int len=mid<<1/*n*/;
node Wn=fpm(3,(MOD-1)/(LL)len);
for(int j=0;j<lim;j+=len){
node w=node(1);
for(int k=0;k<mid;k++){
node x=a[j+k],y=w*a[j+k+mid]%MOD;
a[j+k]=(x+y)%MOD;
a[j+k+mid]=(x-y+MOD)%MOD;
w=w*Wn%MOD;
}
}
}
if(type==-1){
reverse(a+1,a+lim);
node lim_inv=node(inv(lim,MOD.a),inv(lim,MOD.b),inv(lim,MOD.c));
for(int i=0;i<lim;i++)
a[i]=a[i]*lim_inv;
}
}
node a[MAXN],b[MAXN];
int main(){
scanf("%d%d%lld",&N,&M,&Last_Mod);
for(int i=0;i<=N;i++){
LL ii;
scanf("%lld",&ii);
a[i]=node(ii%Last_Mod)%MOD;
}
for(int i=0;i<=M;i++){
LL ii;
scanf("%lld",&ii);
b[i]=node(ii%Last_Mod)%MOD;
}
while(lim<=N+M){
lim<<=1;
lg++;
}
for(int i=0;i<lim;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));
Wn[0]=node(1);
for(int i=1;i<lim;i++)
Wn[i]=Wn[i-1]*INV;
NTT(a,1);
NTT(b,1);
for(int i=0;i<lim;i++)
a[i]=a[i]*b[i]%MOD;
NTT(a,-1);
for(int i=0;i<=N+M;i++)
printf("%lld ",CRT(a[i]));
return 0;
}
例题
模板题:P4245 【模板】任意模数NTT
模板题:【模板】多项式求逆(加强版)
MTT:任意模数NTT的更多相关文章
- 洛谷P4245 【模板】MTT(任意模数NTT)
题目背景 模板题,无背景 题目描述 给定 22 个多项式 F(x), G(x)F(x),G(x) ,请求出 F(x) * G(x)F(x)∗G(x) . 系数对 pp 取模,且不保证 pp 可以分解成 ...
- 【模板】任意模数NTT
题目描述: luogu 题解: 用$fft$水过(什么$ntt$我不知道). 众所周知,$fft$精度低,$ntt$处理范围小. 所以就有了任意模数ntt神奇$fft$! 意思是这样的.比如我要算$F ...
- 任意模数NTT
任意模数\(NTT\) 众所周知,为了满足单位根的性质,\(NTT\)需要质数模数,而且需要能写成\(a2^{k} + r\)且\(2^k \ge n\) 比较常用的有\(998244353,1004 ...
- BZOJ1042 HAOI2008硬币购物(任意模数NTT+多项式求逆+生成函数/容斥原理+动态规划)
第一眼生成函数.四个等比数列形式的多项式相乘,可以化成四个分式.其中分母部分是固定的,可以多项式求逆预处理出来.而分子部分由于项数很少,询问时2^4算一下贡献就好了.这个思路比较直观.只是常数巨大,以 ...
- [洛谷P4245]【模板】任意模数NTT
题目大意:给你两个多项式$f(x)$和$g(x)$以及一个模数$p(p\leqslant10^9)$,求$f*g\pmod p$ 题解:任意模数$NTT$,最大的数为$p^2\times\max\{n ...
- 【知识总结】多项式全家桶(三)(任意模数NTT)
经过两个月的咕咕,"多项式全家桶" 系列终于迎来了第三期--(雾) 上一篇:[知识总结]多项式全家桶(二)(ln和exp) 先膜拜(伏地膜)大恐龙的博客:任意模数 NTT (在页面 ...
- 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT)
再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT) 目录 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Blueste ...
- 洛谷.4245.[模板]任意模数NTT(MTT/三模数NTT)
题目链接 三模数\(NTT\): 就是多模数\(NTT\)最后\(CRT\)一下...下面两篇讲的都挺明白的. https://blog.csdn.net/kscla/article/details/ ...
- 洛谷 P4245 [模板]任意模数NTT —— 三模数NTT / 拆系数FFT(MTT)
题目:https://www.luogu.org/problemnew/show/P4245 用三模数NTT做,需要注意时间和细节: 注意各种地方要取模!传入 upt() 里面的数一定要不超过2倍 m ...
随机推荐
- 分考场(np完全问题,回溯法)
问题描述 n个人参加某项特殊考试. 为了公平,要求任何两个认识的人不能分在同一个考场. 求是少需要分几个考场才能满足条件. 输入格式 第一行,一个整数n(1<n<100),表示参加考试的人 ...
- delphi 窗体的位置和高宽度-TForm:Letf、Top、Width、Height、ClientWidth、ClientHeight
delphi 窗体的位置和高宽度-TForm:Letf.Top.Width.Height.ClientWidth.ClientHeight [窗体的高度和宽度]: [客户区的高度和宽度]: [窗体在屏 ...
- PHP FILTER_SANITIZE_NUMBER_INT 过滤器
定义和用法 FILTER_SANITIZE_NUMBER_INT 过滤器删除数字中所有非法的字符. 该过滤器允许所有数字以及 . + - Name: "number_int" ID ...
- 屏幕尺寸,分辨率,PPI,像素之间的关系
什么是屏幕尺寸? 华为荣耀7的尺寸是5.2英寸.这个5.2英寸是手机屏幕对角线的长度. 1英寸(inch)=2.54厘米(cm) 什么是分辨率? 华为荣耀7的分辨率是1920PX*1080PX.像素是 ...
- obj.offsetHeight与obj.style.height $(obj).height()与$(obj).css('height')
相同:都可以获取obj的高度区别:(1)obj.offsetHeight可以获取外部.内嵌和内联中定义的高,而obj.style.height只能获取内联中定义的高:(2)obj.offsetHeig ...
- bzoj1066题解
[解题思路] 考虑拆点,把每根石柱拆成两个点,具体可以理解为石柱底部和石柱顶部,能爬到石柱顶部的蜥蜴只有有限只,而且蜥蜴只有爬到了石柱顶部才能跳到其他石柱的底部. 这样,考虑如下建图: 将每个有蜥蜴的 ...
- 序列递推——cf1204E(好题)
/* 显然用dp[i][j]来表示i个1,j个-1的结果 dp[i][j]由dp[i-1][j]和dp[i][j-1]转移而来 即dp[i][j]对应的所有序列,都可以由dp[i-1][j]在前面加一 ...
- 51nod-1204 并查集
你的朋友写下一串包含1和0的串让你猜,你可以从中选择一个连续的子串(例如其中的第3到第5个数字)问他,该子串中包含了奇数个还是偶数个1,他会回答你的问题,然后你可以继续提问......你怀疑朋友的答案 ...
- I/O复用select 使用简介
一:五种I/O模型区分: 1.阻塞I/O模型 最流行的I/O模型是阻塞I/O模型,缺省情形下,所有套接口都是阻塞的.我们以数据报套接口为例来讲解此模型(我们使用UDP而不是TCP作为例子的原 ...
- CSS:CSS 盒子模型
ylbtech-CSS:CSS 盒子模型 1.返回顶部 1. CSS 盒子模型 CSS 盒子模型(Box Model) 所有HTML元素可以看作盒子,在CSS中,"box model&quo ...