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来验证网站存在漏洞 如果确认存在漏洞,会随着注入 ...
随机推荐
- 【Android】用Cubism 2制作自己的Live2D——android sdk样本的下载与Android studio编译!
前言- 在浏览Live2d说明书的时候我无意中发现了一个有趣的东西,就是android sdk中居然自带动态壁纸!那就让我们来试试吧,说明书此页的网址连接——中文版||日文版 Android开发所必需 ...
- 一起学Android之ViewPager
本文以一个简单的小例子,简述在Android开发中ViewPager的常见用法,仅供学习分享使用. 概述 ViewPager是一个支持使用者左右滑动的布局管理控件,可以通过一个实现的(适配器)Page ...
- SpringMVC归纳-1(model数据模型与重定向传参技术)
要点: model是一个Map结构的数据模型,能重定向时传递数据(拼接URL),但不安全,主要用于渲染前端页面,配合Thymeleaf填充html里面里设置好的参数. @RequestParam用来获 ...
- Linux下载_Linux系统各种版本ISO镜像下载(redhat,centos,oracle,ubuntu,openSUSE)
以下是风哥收集的Linux系统各种版本ISO镜像下载,包括redhat,centos,oracle,ubuntu等linux操作系统. Linux下载1:红帽RedHat Linux(RHEL5.RH ...
- 使用Server Trigger保护重要的数据库对象
一 .Server Trigger的简单介绍 在SQL Server数据库中,Server Trigger 是一种特殊类型的存储过程,它可以对特定表.视图或存储中的必然事件自动响应,不由用户调用.创建 ...
- iOS NFC
#import <CoreNFC/CoreNFC.h> @interface ViewController ()<NFCNDEFReaderSessionDelegate> @ ...
- (转)postman安装及简单使用
Postman安装与使用 2018-06-04 22:58 by 虫师, 46636 阅读, 10 评论, 收藏, 编辑 Postman一款非常流行的API调试工具.其实,开发人员用的更多.因为测试人 ...
- VS2017打开低版本的VS MVC架构的项目的时候需要修改的地方
1.需要修改的是.sln文件,即将里面的 Version改为12,其中的VS的版本改为2017 2.项目中后缀名为 .csproj中的代码改一下:
- var、let 及 const 区别
var console.log(a) // undefined var a = 1 从上述代码中我们可以发现,虽然变量还没有被声明,但是我们却可以使用这个未被声明的变量,这种情况就叫做提升,并且提升的 ...
- Mybatis 批量添加,批量更新
此篇适合有一定的mybatis使用经验的人阅读. 一.批量更新 为了提升操作数据的效率,第一想到的是做批量操作,直接上批量更新代码: <update id="updateBatchMe ...