几周前搞了搞……有点时间简要整理一下,诸多不足之处还请指出。

 

有哪些需要理解的地方?

  • 点值表示:对于多项式 \(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 简要整理的更多相关文章

  1. Connect2015 简要整理

    2015 简要整理 去年 Connect(); 2014 Visual Studio Contact(); 直播笔记 对于我个人来说,今年 Connect(); 的三个重要发布: ASP.NET 5 ...

  2. GDB用法简要整理

    [时间:2017-05] [状态:Open] [关键词:gdb,调试,debug,用户手册] 使用gdb是需要在编译是指定-g命令,在可执行文件中添加符号信息. 1. 启动和退出 可以使用gdb gd ...

  3. Connect(); // 2015 简要整理

    去年 Connect(); 2014 Visual Studio Contact(); 直播笔记 对于我个人来说,今年 Connect(); 的三个重要发布: ASP.NET 5 RC1 Entity ...

  4. web浏览器兼容简要整理

    ajax的创建 if (window.XMLHttpRequest) { var xhr = new XMLHttpRequest(); } else { //IE6及其以下版本浏览器 var xhr ...

  5. Consul文档简要整理

    什么是Consul? Consul是一个用来实现分布式系统的服务发现与配置的开源工具.他主要由多个组成部分: 服务发现:客户端通过Consul提供服务,类似于API,MySQL,或者其他客户端可以使用 ...

  6. 嵌入式Linux中摄像头使用简要整理【转】

    转自:http://www.cnblogs.com/emouse/archive/2013/03/03/2941938.html 本文涉及软硬件平台: 开发板:飞凌OK6410 系统:Ubuntu 1 ...

  7. 小学生都能看懂的FFT!!!

    小学生都能看懂的FFT!!! 前言 在创新实践重心偷偷看了一天FFT资料后,我终于看懂了一点.为了给大家提供一份简单易懂的学习资料,同时也方便自己以后复习,我决定动手写这份学习笔记. 食用指南: 本篇 ...

  8. hdu 1402(FFT乘法 || NTT乘法)

    A * B Problem Plus Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  9. xss跨站脚本测试

    测试的时候会涉及到xss测试,下面简要整理下xss的知识 xss跨站脚本特点就是能注入恶意的HTML/JS代码到用户浏览器,劫持用户会话 常用alert来验证网站存在漏洞 如果确认存在漏洞,会随着注入 ...

随机推荐

  1. Admin Console 反应慢的相关bug

    一个常见问题是在 Admin console 刷新 server 列表时,页面反应慢.从 Admin Server 的 Thread Dump 可以看到 Admin server 到 Managed ...

  2. EF6实现软删除

    https://www.jianshu.com/p/c65fbfe16e1a

  3. 根据Webservice地址,动态传入参数(Webservice代理类)

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using Sunlib; ...

  4. Windows Server 2016-Telnet 简介及安装

    Telnet是基于请求注释(RFC)854的因特网标准程序和协议,该RFC规定了一种在网络上发送和接收未加密的ASCII字符(明文)的方法.Telnet包含两个功能模块:Telnet客户端和Telne ...

  5. C++11のlambd表达式

    在其他语言中,我们常见lambda表达式,c++11中也引入了. 利用Lambda表达式,可以方便的定义和创建匿名函数.今天,我们就来简单介绍一下C++中Lambda表达式的简单使用. 一.lambd ...

  6. python学习——读取染色体长度(二、向前一步:通过染色体序列获得长度信息)

    # 读取fasta # 解析每条序列的长度 chr1_seq = 'ATATATATAT' chr2_seq = 'ATATATATATCGCGCGCGCG' chr3_seq = 'ATATATAT ...

  7. 017_python常用小技巧

    一.进行十六进制运算 print(hex(int("6500000001", 16) - int("640064c6e7",16))) 0xff9b391a

  8. Ubuntu 14.04 下使用微软的跨平台轻量级开发神器 Visual Studio Code

    因为 Visual Studio Code 不断更新,官方最新 v1.32 的 .deb 包已经不能用于 Ubuntu 14.04 直接安装了. 下载 v1.31 的 deb 包安装即可:https: ...

  9. 使用FreeHttp强制登出微信公众号登陆状态(实现~原理)

    概述 我们使用的部分网站设计成一旦登录即不允许用户手动退出,现实场景中是没有问题的 但如果是在测试或调试过程中就会有强制登出的需求 如果当前使用的是PC浏览器,您或许可以通过调试模式清除保持登录信息的 ...

  10. 类 Calendar

    简介 Java.util.Calendar是日历类,在Date后出现,替换掉了许多Date的方法.该类将所有可能用到的时间信息封装为静态成员变量,方便获取.日历类就是方便获取各个时间属性的.注意Cal ...