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来验证网站存在漏洞 如果确认存在漏洞,会随着注入 ...
随机推荐
- Dotnetcore 开发速记
1.System.InvalidOperationException:"Internal connection fatal error." 全球固定模式,坑爹 https://gi ...
- NET4.6下的UTC时间转换
int UTCSecond = (int)((DateTimeOffset)DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Local)).ToUnix ...
- Android Studio 3.0+ Annotation processors must be explicitly declared now
把Android Studio 升级到3.0+ 版本的时候出现该问题: 可以看到 给了我们两种解决办法: 1. 即 给出现问题的三方 加上 annotationProcessor配置 ...
- Spring boot 发送邮件示例
最近的一个项目中用到了邮件发送,所以研究了一下.将其总结下来. 首先 登录邮箱 -->设置-->POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务--> ...
- jquery实现静态柱形图(写死的数据,只为系统首页UI更美观)
这段时间比较空闲,便阅读公司做好的项目的源代码,学习学习同事的开发思路. 在项目中使用图表可以很好地提高人机交互的友好度,开发的时候看到项目的首页有两个很小的柱形图,很漂亮,便找到对应的代码看了看,发 ...
- SQLServer之创建不可重复读
创建不可重复读注意事项 语法:set transaction isolation level repeatable read. 指定语句不能读取已由其他事务修改但尚未提交的行,并且指定,其他任何事务都 ...
- redis数据库安装 redis持久化及主从复制
----------------------------------------安装redis-5.0.4---------------------------------------- wget h ...
- day22 面向对象
面向对象 ''''1.面向过程编程 核心是"过程"二字,过程指的是解决问题的步骤,即先干什么再干什么 基于该思想编写程序就好比在编写一条流水线,是一种机械式的思维方式 ...
- 记录学习antd design pro dva的过程,主要记错, 多图预警,如有理解偏差,忘指出,多谢!
首要问题: 如何增加菜单项 答案: 在router.config中添加路由,在locales语言国际化增加选项 问题1: 答案1: 问题2: 这个要修改state,正确写法 存在的疑惑:为什么不能直接 ...
- Neutron vxlan network
OpenStack 还支持 vxlan 和 gre 这两种 overlay network. overlay network 是指建立在其他网络上的网络. 该网络中的节点可以看作通过虚拟(或逻辑) ...