任意模数\(NTT\)

众所周知,为了满足单位根的性质,\(NTT\)需要质数模数,而且需要能写成\(a2^{k} + 1\)且\(2^k \ge n\)

比较常用的有\(998244353,1004535809,469762049\),这三个原根都是\(3\)

如果要任意模数怎么办?

\(n\)次多项式在模\(m\)下乘积,最终系数一定不会大于\(nm^2\)

所以我们找三个模数分别做\(NTT\)再合并一下就好辣

但这样的合并结果会爆\(long long\)呢

需要用高精吗?

可以使用一些技巧

我们要合并的是

\[\left \{
\begin{aligned}
x \equiv a_1 \pmod {m_1} \\
x \equiv a_2 \pmod {m_2} \\
x \equiv a_3 \pmod {m_3} \\
\end{aligned}
\right.
\]

我们先在\(long long\)范围内合并前两个

\[\left \{
\begin{aligned}
x \equiv A \pmod M \\
x \equiv a_3 \pmod {m_3} \\
\end{aligned}
\right.
\]

由于最后结果模\(M\)为\(A\),模\(m_3\)为\(a_3\)

设最后的答案是

\[ans = kM + A
\]

且\(k\)需要满足

\[kM + A \equiv a_3 \pmod {m_3}
\]

所以\(k\)一定是在模\(m_3\)意义下求出的,为

\[k \equiv (a_3 - A)M^{-1} \pmod {m_3}
\]

求出\(k\)后就可以直接在原模数意义下求出

\[ans = kM + A
\]

在第一次合并的时候需要快速乘

做三次\(NTT\)常数有够大的

模板题

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define cls(s,v) memset(s,v,sizeof(s))
#define mp(a,b) make_pair<int,int>(a,b)
#define cp pair<int,int>
using namespace std;
const int maxn = 400005,maxm = 100005,INF = 0x3f3f3f3f;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();}
return flag ? out : -out;
}
int pr[]={469762049,998244353,1004535809};
int R[maxn];
inline LL qpow(LL a,LL b,LL p){
LL re = 1; a %= p;
for (; b; b >>= 1,a = a * a % p)
if (b & 1) re = re * a % p;
return re;
}
struct FFT{
int G,P,A[maxn];
void NTT(int* a,int n,int f){
for (int i = 0; i < n; i++) if (i < R[i]) swap(a[i],a[R[i]]);
for (int i = 1; i < n; i <<= 1){
int gn = qpow(G,(P - 1) / (i << 1),P);
for (int j = 0; j < n; j += (i << 1)){
int g = 1,x,y;
for (int k = 0; k < i; k++,g = 1ll * g * gn % P){
x = a[j + k],y = 1ll * g * a[j + k + i] % P;
a[j + k] = (x + y) % P,a[j + k + i] = (x + P - y) % P;
}
}
}
if (f == 1) return;
int nv = qpow(n,P - 2,P); reverse(a + 1,a + n);
for (int i = 0; i < n; i++) a[i] = 1ll * a[i] * nv % P;
}
}fft[3];
int F[maxn],G[maxn],B[maxn],deg1,deg2,deg,md;
LL ans[maxn];
LL inv(LL n,LL p){return qpow(n % p,p - 2,p);}
LL mul(LL a,LL b,LL p){
LL re = 0;
for (; b; b >>= 1,a = (a + a) % p)
if (b & 1) re = (re + a) % p;
return re;
}
void CRT(){
deg = deg1 + deg2;
LL a,b,c,t,k,M = 1ll * pr[0] * pr[1];
LL inv1 = inv(pr[1],pr[0]),inv0 = inv(pr[0],pr[1]),inv3 = inv(M % pr[2],pr[2]);
for (int i = 0; i <= deg; i++){
a = fft[0].A[i],b = fft[1].A[i],c = fft[2].A[i];
t = (mul(a * pr[1] % M,inv1,M) + mul(b * pr[0] % M,inv0,M)) % M;
k = ((c - t % pr[2]) % pr[2] + pr[2]) % pr[2] * inv3 % pr[2];
ans[i] = ((k % md) * (M % md) % md + t % md) % md;
}
}
void conv(){
int n = 1,L = 0;
while (n <= (deg1 + deg2)) n <<= 1,L++;
for (int i = 1; i < n; i++) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
for (int u = 0; u <= 2; u++){
fft[u].G = 3; fft[u].P = pr[u];
for (int i = 0; i <= deg1; i++) fft[u].A[i] = F[i];
for (int i = 0; i <= deg2; i++) B[i] = G[i];
for (int i = deg2 + 1; i < n; i++) B[i] = 0;
fft[u].NTT(fft[u].A,n,1); fft[u].NTT(B,n,1);
for (int i = 0; i < n; i++) fft[u].A[i] = 1ll * fft[u].A[i] * B[i] % pr[u];
fft[u].NTT(fft[u].A,n,-1);
}
}
int main(){
deg1 = read(); deg2 = read(); md = read();
for (int i = 0; i <= deg1; i++) F[i] = read();
for (int i = 0; i <= deg2; i++) G[i] = read();
conv(); CRT();
for (int i = 0; i <= deg; i++) printf("%lld ",ans[i]);
return 0;
}

任意模数NTT的更多相关文章

  1. BZOJ1042 HAOI2008硬币购物(任意模数NTT+多项式求逆+生成函数/容斥原理+动态规划)

    第一眼生成函数.四个等比数列形式的多项式相乘,可以化成四个分式.其中分母部分是固定的,可以多项式求逆预处理出来.而分子部分由于项数很少,询问时2^4算一下贡献就好了.这个思路比较直观.只是常数巨大,以 ...

  2. [洛谷P4245]【模板】任意模数NTT

    题目大意:给你两个多项式$f(x)$和$g(x)$以及一个模数$p(p\leqslant10^9)$,求$f*g\pmod p$ 题解:任意模数$NTT$,最大的数为$p^2\times\max\{n ...

  3. 【模板】任意模数NTT

    题目描述: luogu 题解: 用$fft$水过(什么$ntt$我不知道). 众所周知,$fft$精度低,$ntt$处理范围小. 所以就有了任意模数ntt神奇$fft$! 意思是这样的.比如我要算$F ...

  4. 【知识总结】多项式全家桶(三)(任意模数NTT)

    经过两个月的咕咕,"多项式全家桶" 系列终于迎来了第三期--(雾) 上一篇:[知识总结]多项式全家桶(二)(ln和exp) 先膜拜(伏地膜)大恐龙的博客:任意模数 NTT (在页面 ...

  5. MTT:任意模数NTT

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

  6. 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT)

    再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT) 目录 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Blueste ...

  7. 洛谷.4245.[模板]任意模数NTT(MTT/三模数NTT)

    题目链接 三模数\(NTT\): 就是多模数\(NTT\)最后\(CRT\)一下...下面两篇讲的都挺明白的. https://blog.csdn.net/kscla/article/details/ ...

  8. 洛谷P4245 【模板】MTT(任意模数NTT)

    题目背景 模板题,无背景 题目描述 给定 22 个多项式 F(x), G(x)F(x),G(x) ,请求出 F(x) * G(x)F(x)∗G(x) . 系数对 pp 取模,且不保证 pp 可以分解成 ...

  9. Luogu 4245 【模板】任意模数NTT

    这个题还有一些其他的做法,以后再补,先记一下三模数$NTT$的方法. 发现这个题不取模最大的答案不会超过$10^5 \times 10^9 \times 10^9 = 10^{23}$,也就是说我们可 ...

随机推荐

  1. 在layui中使用ajax不起作用

    又是一个坑,坑了我一个下午.在layui插件中使用jquery的ajax请求,一点反应都没有,不管是改成get还是post请求,后台毫无反应,前端谷歌调试也没有报半点错. js代码如下: layui. ...

  2. C# Note21: 扩展方法(Extension Method)及其应用

    前言 今天在开会时提到的一个概念,入职3个多月多注重在项目中使用C#的编程知识,一直没有很认真地过一遍C#的全部语法,当我们新人被问及是否了解Extension Method时,一时之间竟不能很通俗准 ...

  3. Flutter的scope_model使用mixin语法报错

    在pubspec.yaml同级目录下创建analysis_options.yaml文件,内容: # https://www.dartlang.org/guides/language/analysis- ...

  4. python pip安装找不到指定包的时候怎么解决

    在该网址上下载对应版本的包然后安装即可. https://www.lfd.uci.edu/~gohlke/pythonlibs/

  5. PDO连接mysql数据库加载慢

    今天在使用PDO连接mysql操作数据库的时候,发现速度特别慢,都1~2s的时间,不知道怎么回事,后来一步一步排除到new PDO 导致过慢的原因, 这个尴尬了...,调试了半天都没想到问下度娘,才知 ...

  6. 30行Python代码实现人脸检测

    参考OpenCV自带的例子,30行Python代码实现人脸检测,不得不说,Python这个语言的优势太明显了,几乎把所有复杂的细节都屏蔽了,虽然效率较差,不过在调用OpenCV的模块时,因为模块都是C ...

  7. qtp 自动化测试--点滴 菜单没有了,有些控件运行时找不到

    test项目页签下-没有了 菜单栏:file edit view insert 看不到了 1 解决:在startpage标签下-tool-option-点击 restore layout-确定 2 菜 ...

  8. import、export 和export default區別

    https://www.cnblogs.com/xiaotanke/p/7448383.html

  9. Learning to Rank for IR的评价指标—MAP,NDCG,MRR

    转自: https://www.cnblogs.com/eyeszjwang/articles/2368087.html MAP(Mean Average Precision):单个主题的平均准确率是 ...

  10. LODOP打印控件进行批量打印

    Lodop打印控件批量打印的方式:1.批量打印每页内容相同的:(1)批量打印相同内容的很多纸张,可以设置打印份数,把该内容打印出多份.2.批量打印每页不同内容的:(1)通过在一个任务中分页,循环添加页 ...