网上相关博客不少,这里给自己留个带点注释的模板,以后要是忘了作提醒用。

洛谷3803多项式乘法裸题为例。

FFT:

 #include <cstdio>
#include <cmath>
#include <cctype>
#include <algorithm>
#define ri readint()
#define gc getchar() int readint() {
int x = , s = , c = gc;
while (c <= ) c = gc;
if (c == '-') s = -, c = gc;
for (; isdigit(c); c = gc) x = x * + c - ;
return x * s;
} const int maxn = * 1e6 + ;
const double PI = acos(-1.0); struct Complex {
double x, y;
Complex(double a = , double b = ):x(a), y(b){}
};
Complex operator + (Complex A, Complex B) { return Complex(A.x + B.x, A.y + B.y); }
Complex operator - (Complex A, Complex B) { return Complex(A.x - B.x, A.y - B.y); }
Complex operator * (Complex A, Complex B) { return Complex(A.x * B.x - A.y * B.y, A.x * B.y + A.y * B.x); } Complex a[maxn], b[maxn];
int n, m;
int r[maxn], l, limit = ; void fft(Complex *A, int type) {
for (int i = ; i < limit; i++)
if (i < r[i])
std::swap(A[i], A[r[i]]);
//迭代方式模拟递归写法,需要理解递归是怎么做的才能看懂这个
for (int mid = ; mid < limit; mid <<= ) {
//本来单位根是2*PI/len,这里len替换成2*mid,2就约掉了
Complex Wn(cos(PI / mid), type * sin(PI / mid));
for (int R = mid << , j = ; j < limit; j += R) {
Complex w(, );//单位根的k次幂
for (int k = ; k < mid; k++, w = w * Wn) {
//蝴蝶变换
Complex x = A[j+k], y = w * A[j+k+mid];
A[j+k] = x + y;
A[j+k+mid] = x - y;
}
}
}
} int main() {
n = ri, m = ri;
for (int i = ; i <= n; i++)
a[i].x = ri;
for (int i = ; i <= m; i++)
b[i].x = ri; while (limit <= n + m) {//长度变为2^l
limit <<= ;
l++;
}
for (int i = ; i < limit; i++)//二进制镜像
r[i] = (r[i>>] >> ) | ((i&) << (l-));
fft(a, );
fft(b, );
for (int i = ; i < limit; i++)
a[i] = a[i] * b[i];
fft(a, -);
for (int i = ; i <= n + m; i++)
printf("%d ", (int)(a[i].x / limit + 0.5));
return ;
}

 NTT是用模域取代了复数域,性质相同只是换了单位根,所以板子基本相同。我这两个相比NTT确实比FFT快一点的:

 #include <bits/stdc++.h>
#define ll long long
#define ri readll()
#define gc getchar()
#define rep(i, a, b) for (int i = a; i <= b; i++)
using namespace std; const int P = , G = , Gi = , maxn = * 1e6 + ;
//P的原根为3,3%P的逆元为332748118
//原根意味着:3^(P-1) % P = 1,其中P-1是3%P的阶,本应是φ(P),这里恰好为大素数
ll n, m;
ll a[maxn], b[maxn];
int limit = , l, r[maxn]; ll readll() {
ll x = 0ll, s = 1ll;
char c = gc;
while (c <= ) c = gc;
if (c == '-') s = -1ll, c = gc;
for (; isdigit(c); c = gc) x = x * + c - ;
return x * s;
} ll ksm(ll a, ll b, int mod) {
ll res = 1ll;
for (; b; b >>= ) {
if (b & ) res = res * a % mod;
a = a * a % mod;
}
return res;
} void NTT(ll *A, int flag) {
rep(i, , limit)
if (i < r[i])
swap(A[i], A[r[i]]); for (int mid = ; mid < limit; mid <<= ) {
//如果是变换则单位根为3^[(P-1)/(len)] % P,逆变换则用逆元
ll Wn = ksm(flag ? G : Gi, (P-) / (mid*), P);
for (int R = mid << , j = ; j < limit; j += R) {
ll w = 1ll;
for (int k = ; k < mid; k++, w = w * Wn % P) {
ll x = A[j+k], y = A[j+k+mid] * w % P;
A[j+k] = (x + y) % P;
A[j+k+mid] = (x - y + P) % P;
}
}
}
} int main() {
n = ri, m = ri;
rep(i, , n) a[i] = (ri + P) % P;
rep(i, , m) b[i] = (ri + P) % P; while (limit < n + m + ) {
limit <<= ;
l++;
}
rep(i, , limit) r[i] = (r[i>>] >> ) | ((i & ) << (l - ));
NTT(a, ); NTT(b, );
rep(i, , limit) a[i] = a[i] * b[i] % P;
NTT(a, ); ll inv = ksm(limit, P - , P);//最后变换回来要乘长度的逆元
rep(i, , n + m) printf("%lld ", a[i] * inv % P); return ;
}

FFT与NTT的模板的更多相关文章

  1. 多项式乘法,FFT与NTT

    多项式: 多项式?不会 多项式加法: 同类项系数相加: 多项式乘法: A*B=C $A=a_0x^0+a_1x^1+a_2x^2+...+a_ix^i+...+a_{n-1}x^{n-1}$ $B=b ...

  2. FFT,NTT 专题

    学习傅里叶的基本性质及其代码,可以参考大神理解 还有 ACdream 的博客 贴一下NTT的模板: using namespace std; typedef long long ll; int n; ...

  3. FFT和NTT学习笔记_基础

    FFT和NTT学习笔记 算法导论 参考(贺) http://picks.logdown.com/posts/177631-fast-fourier-transform https://blog.csd ...

  4. fft,ntt总结

    一个套路:把式子推成卷积形式,然后用fft或ntt优化求解过程. fft的扩展性不强,不可以在fft函数里多加骚操作--DeepinC T1:多项式乘法 板子题 T2:快速傅立叶之二 另一个板子,小技 ...

  5. 多项式fft、ntt、fwt 总结

    做了四五天的专题,但是并没有刷下多少题.可能一开始就对多项式这块十分困扰,很多细节理解不深. 最简单的形式就是直接两个多项式相乘,也就是多项式卷积,式子是$N^2$的.多项式算法的过程就是把卷积做一种 ...

  6. FFT与NTT专题

    先不管旋转操作,考虑化简这个差异值 $$begin{aligned}sum_{i=1}^n(x_i-y_i-c)^2&=sum_{i=1}^n(x_i-y_i)^2+nc^2-2csum_{i ...

  7. 洛谷 - P3803 -【模板】多项式乘法(FFT) - NTT

    https://www.luogu.org/problemnew/show/P3803 看别人偏偏就是要用NTT去过.实验证明大概是这样用.求0~n的多项式和0~m的多项式的乘积.注意MAXN取值.A ...

  8. luoguP4721 【模板】分治 FFT (分治NTT)

    给定 $g[1....n-1]$,求 $f[0],f[1],...,f[n-1]$,其中   $f[i]=\sum_{j=1}^{i}f[i-j]g[j]$    变界为 $f[0]=1$ 答案模 9 ...

  9. 卷积FFT、NTT、FWT

    先简短几句话说说FFT.... 多项式可用系数和点值表示,n个点可确定一个次数小于n的多项式. 多项式乘积为 f(x)*g(x),显然若已知f(x), g(x)的点值,O(n)可求得多项式乘积的点值. ...

随机推荐

  1. wav音频文件头解析

    wav概述 WAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(ResourceInterchange File Format)文件规范,用于保存Windows平台的音频信息 ...

  2. BestCoder7 1001 Little Pony and Permutation(hdu 4985) 解题报告

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4985 题目意思:有 n 个数,对于第 i 个数给出 σ(i) 的值.求出互不相交的循环的个数,并输出每 ...

  3. 编译Thrift

    按照 https://syslint.com/blog/tutorial/how-to-install-apache-thrift-on-ubuntu-14-04/ 进行, 编译时出现错误 make[ ...

  4. deepin软件中文乱码

    如图所示,deepin软件,会有这种情况,中文全是乱码,口口口.这表示很讨厌,学长给出的解决办法,将系统换成英文语言,这样确实解决了乱码,但是还是有问题,比如在写中文注释,又变成这样了. 去deepi ...

  5. hdu-4990 Reading comprehension(快速幂+乘法逆元)

    题目链接: Reading comprehension Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 32768/32768 K ( ...

  6. 「LuoguP1341」 无序字母对(欧拉回路

    题目描述 给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒).请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现. 输入输出格式 输入格式: 第一行输入一 ...

  7. 采用Psyco实现python执行速度提高到与编译语言一样的水平

    本文实例讲述了采用Psyco实现python执行速度提高到与编译语言一样的水平的方法,分享给大家供大家参考.具体实现方法如下: 一.安装Psyco很简单,它有两种安装方式,一种是源码方式,一种是二进制 ...

  8. P1115最大子段和

    题目:https://www.luogu.org/problemnew/show/P1115 很简明的一道题: 这里用了递归分治,然而似乎还有更简单的做法(贪心). 代码如下: #include< ...

  9. JAVA 需要理解的重点 二

    1.常用设计模式 单例模式:懒汉式.饿汉式.双重校验锁.静态加载,内部类加载.枚举类加载.保证一个类仅有一个实例,并提供一个访问它的全局访问点. 代理模式:动态代理和静态代理,什么时候使用动态代理. ...

  10. linux下监控用户的操作记录---录像播放性质

    想知道用户登陆系统后都操作了什么,怎么办? 别急,linux下有一个script工具,专门记录终端会话中所有输入输出结果,并存放到指定文件中. 先看看怎么录制吧! 1.创建日志存放目录 # mkdir ...