Luogu 4245 【模板】任意模数NTT
这个题还有一些其他的做法,以后再补,先记一下三模数$NTT$的方法。
发现这个题不取模最大的答案不会超过$10^5 \times 10^9 \times 10^9 = 10^{23}$,也就是说我们可以取三个满足$NTT$性质的模数先算然后再合并起来。
比如三个模数可以分别取$998244353, 1004535809, 469762049$。
那么我们现在要做的就是合并三个同余方程:
$$x \equiv a_1(\mod P_1)$$
$$x \equiv a_2(\mod P_2)$$
$$x \equiv a_3(\mod P_3)$$
直接上$crt$的话会爆$long \ long$,我们需要一些其他技巧。
先用$crt$合并前两个方程,记
$$t = a_1P_2 \times inv(P_2, P_1) + a_2P_1 \times inv(P_1, P_2) $$
相当于
$$x \equiv t (\mod M = P_1P_2)$$
我们设$x = kM + t$,代入第三个方程,
$$kM + t \equiv a_3(\mod P_3)$$
可以解
$$k \equiv (a_3 - t) \times inv(M, P_3) (\mod P_3)$$
最后代回去算出$kM + t$即可。
在计算$t$的时候需要快速乘。
时间复杂度$O(nlogn)$。
注意到几个逆元没有必要计算多次,可以节省大量常数;用$O(1)$快速乘也可以大大加快速度。
Code:
// luogu-judger-enable-o2
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll; const int N = 3e5 + ;
const ll Mod[] = {998244353LL, 1004535809LL, 469762049LL}; int n, m, lim = , pos[N];
ll a[N], b[N], tmp[N], ans[][N]; template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for (; ch > '' || ch < ''; ch = getchar())
if (ch == '-') op = -;
for (; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} template <typename T>
inline void swap(T &x, T &y) {
T t = x; x = y; y = t;
} inline ll fmul(ll x, ll y, ll P) {
ll res = 0LL;
for (; y; y >>= ) {
if (y & ) res = (res + x) % P;
x = (x + x) % P;
}
return res;
} inline ll fpow(ll x, ll y, ll P) {
ll res = 1LL;
/* for (; y > 0; y >>= 1) {
if (y & 1) res = fmul(res, x, P);
x = fmul(x, x, P);
} */ for (; y > ; y >>= ) {
if (y & ) res = res * x % P;
x = x * x % P;
} return res;
} inline ll getInv(ll x, ll y) {
return fpow(x % y, y - , y);
} inline void prework() {
int l = ;
for (; lim <= n + m; lim <<= , ++l);
for (int i = ; i < lim; i++)
pos[i] = (pos[i >> ] >> ) | ((i & ) << (l - ));
} inline void ntt(ll *c, int opt, ll P) {
for (int i = ; i < lim; i++)
if (i < pos[i]) swap(c[i], c[pos[i]]);
for (int i = ; i < lim; i <<= ) {
ll wn = fpow(, (P - ) / (i << ), P);
if (opt == -) wn = fpow(wn, P - , P);
for (int len = i << , j = ; j < lim; j += len) {
ll w = 1LL;
for (int k = ; k < i; k++, w = w * wn % P) {
ll x = c[j + k], y = w * c[j + k + i] % P;
c[j + k] = (x + y) % P, c[j + k + i] = (x - y + P) % P;
}
}
} if (opt == -) {
ll inv = getInv(lim, P);
for (int i = ; i < lim; i++) c[i] = c[i] * inv % P;
}
} inline void solve(int id) {
for (int i = ; i < lim; i++)
tmp[i] = b[i] % Mod[id], ans[id][i] = a[i] % Mod[id];
ntt(tmp, , Mod[id]), ntt(ans[id], , Mod[id]);
for (int i = ; i < lim; i++) ans[id][i] = ans[id][i] * tmp[i] % Mod[id];
ntt(ans[id], -, Mod[id]);
} inline ll get(int k, ll P) {
ll M = (Mod[] * Mod[]);
ll t1 = fmul(ans[][k] * Mod[] % M, getInv(Mod[], Mod[]), M);
ll t2 = fmul(ans[][k] * Mod[] % M, getInv(Mod[], Mod[]), M);
ll t = (t1 + t2) % M;
ll invM = getInv(M, Mod[]), c = t;
t = (ans[][k] - t % Mod[] + Mod[]) % Mod[];
t = t * invM % Mod[];
return ((M % P) * (t % P) % P + c % P) % P;
} int main() {
ll P;
read(n), read(m), read(P);
for (int i = ; i <= n; i++) {
read(a[i]);
a[i] %= P;
}
for (int i = ; i <= m; i++) {
read(b[i]);
b[i] %= P;
} prework();
for (int i = ; i < ; i++) solve(i); /* for (int i = 0; i < 3; i++, printf("\n"))
for (int j = 0; j < lim; j++)
printf("%lld ", ans[i][j]); */ for (int i = ; i <= n + m; i++)
printf("%lld%c", get(i, P), i == (n + m) ? '\n' : ' '); return ;
}
Luogu 4245 【模板】任意模数NTT的更多相关文章
- 洛谷.4245.[模板]任意模数NTT(MTT/三模数NTT)
题目链接 三模数\(NTT\): 就是多模数\(NTT\)最后\(CRT\)一下...下面两篇讲的都挺明白的. https://blog.csdn.net/kscla/article/details/ ...
- [题解] Luogu P4245 [模板]任意模数NTT
三模NTT 不会... 都0202年了,还有人写三模NTT啊... 讲一个好写点的做法吧: 首先取一个阀值\(w\),然后把多项式的每个系数写成\(aw + c(c < w)\)的形式,换句话说 ...
- 洛谷 P4245 [模板]任意模数NTT —— 三模数NTT / 拆系数FFT(MTT)
题目:https://www.luogu.org/problemnew/show/P4245 用三模数NTT做,需要注意时间和细节: 注意各种地方要取模!传入 upt() 里面的数一定要不超过2倍 m ...
- 【模板】任意模数NTT
题目描述: luogu 题解: 用$fft$水过(什么$ntt$我不知道). 众所周知,$fft$精度低,$ntt$处理范围小. 所以就有了任意模数ntt神奇$fft$! 意思是这样的.比如我要算$F ...
- [洛谷P4245]【模板】任意模数NTT
题目大意:给你两个多项式$f(x)$和$g(x)$以及一个模数$p(p\leqslant10^9)$,求$f*g\pmod p$ 题解:任意模数$NTT$,最大的数为$p^2\times\max\{n ...
- 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT)
再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT) 目录 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Blueste ...
- 任意模数NTT
任意模数\(NTT\) 众所周知,为了满足单位根的性质,\(NTT\)需要质数模数,而且需要能写成\(a2^{k} + r\)且\(2^k \ge n\) 比较常用的有\(998244353,1004 ...
- BZOJ1042 HAOI2008硬币购物(任意模数NTT+多项式求逆+生成函数/容斥原理+动态规划)
第一眼生成函数.四个等比数列形式的多项式相乘,可以化成四个分式.其中分母部分是固定的,可以多项式求逆预处理出来.而分子部分由于项数很少,询问时2^4算一下贡献就好了.这个思路比较直观.只是常数巨大,以 ...
- 【知识总结】多项式全家桶(三)(任意模数NTT)
经过两个月的咕咕,"多项式全家桶" 系列终于迎来了第三期--(雾) 上一篇:[知识总结]多项式全家桶(二)(ln和exp) 先膜拜(伏地膜)大恐龙的博客:任意模数 NTT (在页面 ...
- MTT:任意模数NTT
MTT:任意模数NTT 概述 有时我们用FFT处理的数据很大,而模数可以分解为\(a\cdot 2^k+1\)的形式.次数用FFT精度不够,用NTT又找不到足够大的模数,于是MTT就应运而生了. MT ...
随机推荐
- 初学HTML之HTML介绍
众所周知现在的H5.大数据.云计算都是热门的.其实想学好一门语言重点是多看多想多写多练. 我在博客中会从基础开始讲解HTML4.0.中间加入HTML5的新标签 在这先给大家推荐几个开发工具: note ...
- 批处理实现mysql的备份
脚本 @echo off echo. echo MySQL数据库备份 echo ***************************** echo. echo 今天是 %date% echo 时间是 ...
- javascript基础-js对象
一.js对象的创建 1.普通最简单的方式 var teacher = new Object( ); teacher.name = "zhangsan"; teacher.age = ...
- FPGA之外,了解一下中断
中断是什么? 中断的汉语解释是半中间发生阻隔.停顿或故障而断开.那么,在计算机系统中,我们为什么需要“阻隔.停顿和断开”呢? 举个日常生活中的例子,比如说我正在厨房用煤气烧一壶水,这样就只能守在厨房里 ...
- GOF23设计模式之备忘录模式(memento)
一.备忘录模式概述 保存某个对象内部状态的拷贝,使得以后就可以将该对象恢复到原先的状态. 结构: (1)源发器类 Originator 负责创建一个备忘录 Memento,用以记录当前时刻它的内部 ...
- Java报错 -- The public type c must be defined in its own file
出现The public type c must be defined in its own file这个问题,是由于定义的JAVA类同文件名不一致 你的文件里很可能有两个 public 的类,而Ja ...
- 【BZOJ】1878: [SDOI2009]HH的项链 (主席树)
题目 传送门:QWQ 分析 莫队也能做,但我想练练主席树. 求k-th一样维护第i个时候的线段树,线段树来维护区间不同数. 然后查询时可以通过上下界小优化一波. 但是我的代码丑陋无比,常数巨大(捂脸 ...
- 浏览器发起Get,Post请求时候传递的参数编码问题
浏览器发起Get,Post请求时候传递的参数编码问题 最近开发一个网站的时候,用了很多ajax方法,在页面发起Get,post请求,中间自然捎带有很多参数,有中文,有英文,英文一般是不存在编码问题的, ...
- windows administrator提升system
最近刚好有这个需求,本想开一个super cmd,但是win10上不兼容不太好. 于是使用PsExec来提升system权限. 微软传送地址:https://docs.microsoft.com/en ...
- OD 实验(八) - 对一个程序的逆向
程序: 运行 弹出 NAG 窗口,提示要花 20 美元注册 然后会进入主窗口 提示剩余 5 天的使用时间 点击,菜单栏 -> Help -> About 显示未注册版本 逆向: 用 OD ...