FFT & FNT 简要整理
几周前搞了搞……有点时间简要整理一下,诸多不足之处还请指出。
有哪些需要理解的地方?
- 点值表示:对于多项式 \(A(x)\),把 \(n\) 个不同的 \(x\) 代入,会得出 \(n\) 个不同的 \(y\),在坐标系内就是 \(n\) 个不同的点,那么这 \(n\) 个点唯一确定该多项式
- 为什么引入单位根 \(\omega\) 作为变量 \(x\):若代入一些 \(x\) ,使每个 \(x\) 的若干次方等于 \(1\),就不用做全部的次方运算了
- 单位根的性质:于是可以分治实现 \(FFT\),复杂度降至 \(O(n log n)\)
- 共轭复数:复数 \(z=a+bi\) 的共轭复数为 \(a−bi\)(虚部取反)。一个多项式在分治的过程中乘上单位根的共轭复数,分治完的每一项除以 \(n\) 即为原多项式的每一项系数
- 初始化序列反转二进制数 : \(r[i] = (r[i >> 1] >> 1) | ((i \& 1) << (l - 1))\)
- 利用二进制序列优化 \(FFT\):每个位置分治后的最终位置为其二进制翻转后得到的位置
算法的步骤?
- 输入,将向量长度转化成二的幂次
- 初始化序列反转二进制数 : \(r[i] = (r[i >> 1] >> 1) | ((i \& 1) << (l - 1))\)
- 利用 \(FFT\) 将多项式转化为点值表示,如下:
- 利用处理出的二进制求出待处理序列
- 分治,每次找序列的一半,利用单位根计算(乘上 \(k\) 次幂),后对称到另一半
- 将点值表示相乘,利用 \(IFFT\) 将其转换回系数表达式,输出
- 多项式在分治的过程中乘上单位根的共轭复数,分治完的每一项除 \(n\) 即为原多项式的每一项系数
\(NTT\) 其实就是在模意义下做了些许改变,十分类似。 - \(NTT\) 模数:原根为 \(3\),有 \(469762049\),\(998244353\),\(1004535809\)
- 原根在此特殊意义下代替了单位根,除法相应地变成逆元的乘法运算
- 在模数并不是 \(NTT\) 模数时,采用 \(MTT\) 或三模数 \(NTT\) + \(CRT\)
\(FFT\) 和 \(FNT\) 板子?
// Fast_fourier_transform
#include <cmath>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const double pi = acos(-1.0);
const int maxn = 5000000 + 10;
int n, m, len, limit, rado, r[maxn];
struct Complex {
double x, y;
Complex(double tx = 0, double ty = 0) { x = tx, y = ty; }
} f_1[maxn], f_2[maxn];
inline Complex operator + (const Complex &a, const Complex &b) { return Complex(a.x + b.x, a.y + b.y); }
inline Complex operator - (const Complex &a, const Complex &b) { return Complex(a.x - b.x, a.y - b.y); }
inline Complex operator * (const Complex &a, const Complex &b) { return Complex(a.x * b.x - a.y * b.y, a.x * b.y + b.x * a.y); }
inline int read() {
register char ch = 0; register int w = 0, x = 0;
while( !isdigit(ch) ) w |= (ch == '-'), ch = getchar();
while( isdigit(ch) ) x = (x * 10) + (ch ^ 48), ch = getchar();
return w ? -x : x;
}
inline void Fast_fourior_transform(Complex *a, int type) {
for(int i = 0; i < limit; ++i) if( i < r[i] ) swap(a[i], a[r[i]]);
for(int mid = 1; mid < limit; mid = mid << 1) {
Complex Base_w = Complex(cos(pi / mid), type * sin(pi / mid));
for(int len = mid << 1, l = 0; l < limit; l = l + len) {
Complex w = Complex(1, 0);
for(int k = 0; k < mid; ++k, w = w * Base_w) {
Complex tmp_1 = a[l + k], tmp_2 = w * a[l + mid + k];
a[l + k] = tmp_1 + tmp_2, a[l + mid + k] = tmp_1 - tmp_2;
}
}
}
}
int main(int argc, char const *argv[])
{
freopen("..\\nanjolno.in", "r", stdin);
freopen("..\\nanjolno.out", "w", stdout);
scanf("%d%d", &n, &m);
for(int i = 0; i <= n; ++i) f_1[i].x = read();
for(int i = 0; i <= m; ++i) f_2[i].x = read();
len = n + m, limit = 1, rado = 0;
while( limit <= len ) limit = limit << 1, ++rado;
for(int i = 0; i < limit; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (rado - 1));
Fast_fourior_transform(f_1, 1);
Fast_fourior_transform(f_2, 1);
for(int i = 0; i < limit; ++i) f_1[i] = f_1[i] * f_2[i];
Fast_fourior_transform(f_1, -1);
for(int i = 0; i <= len; ++i) printf("%d\n", (int)(f_1[i].x / limit + 0.1));
fclose(stdin), fclose(stdout);
return 0;
}
// Fast_number_theory_transform
#include <cmath>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int mod = 998244353;
const int maxn = 5000000 + 10;
int n, m, len, limit, rado, f_1[maxn], f_2[maxn], r[maxn];
inline int read() {
register char ch = 0; register int w = 0, x = 0;
while( !isdigit(ch) ) w |= (ch == '-'), ch = getchar();
while( isdigit(ch) ) x = (x * 10) + (ch ^ 48), ch = getchar();
return w ? -x : x;
}
inline int Fast_pow(int a, int p) {
long long x = a, ans = 1ll;
for( ; p; x = x * x % mod, p = p >> 1) if( p & 1 ) ans = x * ans % mod;
return (int)ans;
}
inline void Fast_numbertheory_transform(int *a, int limit, int type) {
int rado = bit[limit];
for(int i = 0; i < limit; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (rado - 1));
for(int i = 0; i < limit; ++i) if( i < r[i] ) swap(a[i], a[r[i]]);
for(int mid = 1; mid < limit; mid = mid << 1) {
int Base_p = Fast_pow(3ll, (mod - 1) / (mid << 1));
if( type == -1 ) Base_p = Fast_pow(Base_p, mod - 2);
for(int l = 0, length = mid << 1; l < limit; l = l + length) {
for(int k = 0, p = 1; k < mid; ++k, p = 1ll * p * Base_p % mod) {
int x = a[l + k], y = 1ll * p * a[l + mid + k] % mod;
a[l + k] = (x + y) % mod, a[l + mid + k] = (x - y + mod) % mod;
}
}
}
if( type == -1 ) for(int i = 0; i < limit; ++i) a[i] = 1ll * a[i] * Fast_pow(limit, mod - 2) % mod;
}
int main(int argc, char const *argv[])
{
freopen("..\\nanjolno.in", "r", stdin);
freopen("..\\nanjolno.out", "w", stdout);
scanf("%d%d", &n, &m);
for(int i = 0; i <= n; ++i) f_1[i] = read();
for(int i = 0; i <= m; ++i) f_2[i] = read();
len = n + m, limit = 1, rado = 0;
while( limit <= len ) limit = limit << 1, ++rado;
for(int i = 0; i < limit; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (rado - 1));
Fast_numbertheory_transform(f_1, 1);
Fast_numbertheory_transform(f_2, 1);
for(int i = 0; i < limit; ++i) f_1[i] = 1ll * f_1[i] * f_2[i] % mod;
Fast_numbertheory_transform(f_1, -1);
for(int i = 0; i <= len; ++i) printf("%d ", f_1[i]);
fclose(stdin), fclose(stdout);
return 0;
}
流萤断续光,一明一灭一尺间,寂寞何以堪。
FFT & FNT 简要整理的更多相关文章
- Connect2015 简要整理
2015 简要整理 去年 Connect(); 2014 Visual Studio Contact(); 直播笔记 对于我个人来说,今年 Connect(); 的三个重要发布: ASP.NET 5 ...
- GDB用法简要整理
[时间:2017-05] [状态:Open] [关键词:gdb,调试,debug,用户手册] 使用gdb是需要在编译是指定-g命令,在可执行文件中添加符号信息. 1. 启动和退出 可以使用gdb gd ...
- Connect(); // 2015 简要整理
去年 Connect(); 2014 Visual Studio Contact(); 直播笔记 对于我个人来说,今年 Connect(); 的三个重要发布: ASP.NET 5 RC1 Entity ...
- web浏览器兼容简要整理
ajax的创建 if (window.XMLHttpRequest) { var xhr = new XMLHttpRequest(); } else { //IE6及其以下版本浏览器 var xhr ...
- Consul文档简要整理
什么是Consul? Consul是一个用来实现分布式系统的服务发现与配置的开源工具.他主要由多个组成部分: 服务发现:客户端通过Consul提供服务,类似于API,MySQL,或者其他客户端可以使用 ...
- 嵌入式Linux中摄像头使用简要整理【转】
转自:http://www.cnblogs.com/emouse/archive/2013/03/03/2941938.html 本文涉及软硬件平台: 开发板:飞凌OK6410 系统:Ubuntu 1 ...
- 小学生都能看懂的FFT!!!
小学生都能看懂的FFT!!! 前言 在创新实践重心偷偷看了一天FFT资料后,我终于看懂了一点.为了给大家提供一份简单易懂的学习资料,同时也方便自己以后复习,我决定动手写这份学习笔记. 食用指南: 本篇 ...
- hdu 1402(FFT乘法 || NTT乘法)
A * B Problem Plus Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- xss跨站脚本测试
测试的时候会涉及到xss测试,下面简要整理下xss的知识 xss跨站脚本特点就是能注入恶意的HTML/JS代码到用户浏览器,劫持用户会话 常用alert来验证网站存在漏洞 如果确认存在漏洞,会随着注入 ...
随机推荐
- java 线程方法 ---- wait()
class MyThread5 implements Runnable{ private int flag = 10; @Override public void run() { while (fla ...
- 逐个使用C++11新特性
C++11 auto & decltype auto:根据变量初始值来推导变量类型,并用右值初始化变量. decltype:从表达式推导出类型,并将变量定义为该类型,但不用表达式的值初始化该变 ...
- qt生成二维码
到官网下载qrencode http://fukuchi.org/works/qrencode/index.html.en qrenc.c不用,这个是测试用的,把config.h.in文件改为conf ...
- EF Code First 连接MySql
看了很多文章,尝试了很多次总是进行不下去,整理一下,以便日后查看. 1.创建ASP.NET MVC项目(EFCodeFirst) 1.1.右键点击引用选择管理NuGet程序包下载MySql.Data. ...
- windows压缩图片
- 在Windows7中的DPI与主题的问题
测试环境Windows7x64,vb6.0 测试在XP系统下,DPI计算似乎没问题 Screen.TwipsPerPixelX=1440/DPI=1440/96=15Screen.TwipsPerPi ...
- java 浅复制 代码
1 类实现Cloneable接口 2 重写clone()方法 3 类变量引用类型无法复制 class Dog extends Pet implements Cloneable{ int c; i ...
- python接口自动化-Cookie_绕过验证码登录
前言 有些登录的接口会有验证码,例如:短信验证码,图形验证码等,这种登录的验证码参数可以从后台获取(或者最直接的可查数据库) 获取不到也没关系,可以通过添加Cookie的方式绕过验证码 前面在“pyt ...
- FLIR 相机采集程序
https://www.ptgrey.com/Downloads/GetSecureDownloadItem/11048 Grasshopper3 4.1 MP Mono USB3 Vision (C ...
- Visual Studio 2019 正式版 更新内容
大早上更新了Visual Studio 2019, 试用一下 一.界面改变 1.项目创建界面 首先启动界面改变就不说了,创建项目的界面做了较大改变,感觉在向vs for mac 靠拢 ,而后者感觉像x ...