【基础操作】FFT / DWT / NTT / FWT 详解
1.
2. 点值表示法
假设两个多项式相乘后得到的多项式 的次数(最高次项的幂数)为 $n$。(这个很好求,两个多项式的最高次项的幂数相加就得到了)
对于每个点,要用 $O(n)$ 的时间 把 $x$ 分别代入两个多项式,得到两个结果 $z_1,z_2$,两者相乘得到 $z$,才能知道相乘后的多项式在代入一个 $x$ 时会得到 $z$,也就是固定了一个点 $(x,z)$。
至少需要 $n$ 个点(也就是枚举 $n$ 个 $x$)才能确定一个 $n$ 次多项式(拉格朗日插值),总时间复杂度 $O(n^2)$,跟暴力差不多。
$FFT$(Fast Fourier transform,快速傅里叶变换)
$DFT$
$IDFT$
$NTT$(Number-Theoretic Transform,快速数论变换)
在 $FFT$ 中,我们需要用到复数,复数虽然很神奇,但是它也有自己的局限性——
$1$ 是需要用 $double$ 类型计算,精度太低;
$2$ 是复数是虚数,它里面的 $i=\sqrt(-1)$,并不能取模。
那有没有什么东西能够代替复数且解决精度问题呢?
这个东西,叫原根
对于高中的 $OIer$ 而言,暂时不用证明这种没法证明的数学知识,记个结论就行了,其实现也只需要在普通的 $FFT$ 上改一点点。
阶
若 $a,p$ 互素,且 $p>1$,
对于 $a^n≡1 \pmod p$ 最小的 $n$,我们称之为 $a$ 模 $p$ 的阶,记做 $\delta_p(a)$。也就是 $n=\delta_p(a)$。
例如:
$δ7(2)=3$
$2^1≡2\space \pmod7$
$2^2≡4\space \pmod7$
$2^3≡1\space \pmod7$
原根
定义:设 $p$ 是正整数,$a$ 是整数,若 $\delta_p(a)$ 等于 $\varphi(p)$,则称 $a$ 为模 $p$ 的一个原根。
$\delta_7(3)=6=\varphi(7)$,因此 $3$ 是模 $7$ 的一个原根。
注意原根的个数是不唯一的。
这位同学讲得真好!
辅助结论(暂时对代码无帮助)
1. 如果模数 $p$ 有原根,那么它一定有 $\varphi(\varphi(p))$ 个原根。也就是说有些整数 $a$ 可能没有原根。
其实原根存在的充要条件为 $p ∈ {1,2,4,p^n}$,其中 $p$ 为奇素数且 $n$ 是任意正整数。
2. 若 $P$ 为素数,假设一个数 $g$ 是 $P$ 的原根,那么 $g_i\mod P\space (1\lt g\lt P,\space 0\lt i\lt P)$ 的结果两两不同。
用处
原根能代替单位根进行运算,是因为它具有和单位根相同的性质。
在 $FFT$ 中,我们用到了单位根的 $4$ 种性质,而原根也满足这 $4$ 条性质。
最终有个结论:$$\omega_n \equiv g^\frac{p-1}{n} \mod p$$
然后把 $FFT$ 中的 $\omega_n$ 全都换成上面这个即可。
由于多出来的快速幂是套在最外层的 $log$ 级别循环里的,因此 $NTT$ 的时间复杂度跟 $FFT$ 一样,是 $O(n\times log(n))$ 的(但是带大常数,因为分治内快速幂部分的复杂度实际上略高于 $O(log(n))$)。
怎么用代码求原根
$OI$ 的常见模数是 $P=998244353$,其原根 $n$ 为 $3$,原根的逆元为 $998244354÷3=332748118$(做 $IDFT$ 时要把之前 $DFT$ 乘的项除掉,而除法得改成乘逆元)。这个模数可以直接背。
如果一道题给了其它的模数,你可以在本机根据定义暴力求原根。
首先考虑求 $\varphi(p)$。
判断一下模数是不是素数($O(\sqrt n)$ 就能判断,很快的),如果是的话,$\varphi(n)$ 就等于 $n-1$(忘了的建议回去复习下欧拉函数);
否则求 $\varphi(n)$ 的值(其实时间复杂度也是 $O(\sqrt n)$),本机跑完后取出结果就行啦。
因为对于阶的定义式 $a^n\equiv 1\pmod p$,我们定义了 $n=\delta_p(a)=\varphi(p)$,所以把 $\varphi(p)$ 代回 $n$,再暴力枚举一些原根 $a$ ,找到一个满足原式子的 $a$ 即可。一般的习惯是从小到大枚举正整数为原根。
由于你只需要在本机跑出一个原根,提出来即可,所以不用太管时间复杂度……
好像结束了吧
不,显然还没结束。不知道你有没有注意到这样一个问题:$a^n≡1 \pmod p$ 这个式子,如果 $a$ 取 $1$,那它在定义域内肯定是满足要求的,也就是说 $1$ 好像是可以直接取的通用原根?
那我们还暴力找原根干啥?
这说明你忘了原根的意义。
原根是用来代替 $FFT$ 中的 $\omega$ 的,而我们用 $\omega$ 是为了取 $n$ 个有特殊性质的不同点。
对,点值表示法一开始就说过,必须代入 $n$ 个不同的点,也就是 $n$ 个不同的取值 $x$。
显然,如果取 $a=1$,那 $a^n$ 的所有取值都相同,就不满足点值表示法的本质要求了。
所以原根不能取 $1$。
对于 $a$ 的其它取值,之前还说过一个辅助结论,进一步印证了 取不等于 $1$ 且在范围内的原根都是满足要求的:
若 $P$ 为素数,假设一个数 $g$ 是 $P$ 的原根,那么 $g_i\mod P\space (1\lt g\lt P,\space 0\lt i\lt P)$ 的结果两两不同。
FWT(Fast Walsh-Hadamard Transform,快速沃尔什变换)
结语
以前看到 $FFT$ 什么的数论神仙知识,总感觉很恶心,不是我这种蒟蒻可学的。
但现在真的学,加起来其实只学了 $2$ 天,就差不多搞明白了。
$OI$ 界的数学知识,并不要求你都严格证明,有些太叼的数学知识你可以先记个结论。
另外 $FFT$ 什么的东西都是数学板子,全文背诵都可以……
忠告:$FFT$ 系列的板子的常数都比较大,大约在 $n\le 200$ 时都跑得不如暴力快。
【基础操作】FFT / DWT / NTT / FWT 详解的更多相关文章
- 【基础操作】博弈论 / SG 函数详解
		博弈死我了……(话说哪个小学生会玩博弈论提到的这类弱智游戏,还取石子) 先推荐两个文章链接:浅谈算法——博弈论(从零开始的博弈论) 博弈论相关知识及其应用 This article was updat ... 
- GoLang基础数据类型--->字典(map)详解
		GoLang基础数据类型--->字典(map)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 可能大家刚刚接触Golang的小伙伴都会跟我一样,这个map是干嘛的,是 ... 
- GoLang基础数据类型-切片(slice)详解
		GoLang基础数据类型-切片(slice)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 数组的长度在定义之后无法再次修改:数组是值类型,每次传递都将产生一份副本.显然这种数 ... 
- GoLang基础数据类型--->数组(array)详解
		GoLang基础数据类型--->数组(array)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Golang数组简介 数组是Go语言编程中最常用的数据结构之一.顾名 ... 
- Java基础-反射(reflect)技术详解
		Java基础-反射(reflect)技术详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.类加载器 1>.JVM 类加载机制 如下图所示,JVM类加载机制分为五个部分 ... 
- Java基础-DBCP连接池(BasicDataSource类)详解
		Java基础-DBCP连接池(BasicDataSource类)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程 ... 
- Java基础13:反射与注解详解
		Java基础13:反射与注解详解 什么是反射? 反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性. Orac ... 
- kafka实战教程(python操作kafka),kafka配置文件详解
		kafka实战教程(python操作kafka),kafka配置文件详解 应用往Kafka写数据的原因有很多:用户行为分析.日志存储.异步通信等.多样化的使用场景带来了多样化的需求:消息是否能丢失?是 ... 
- Python中操作mysql的pymysql模块详解
		Python中操作mysql的pymysql模块详解 前言 pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同.但目前pymysql支持python3.x而后者不支持 ... 
随机推荐
- sql service 查询分析数据库
			--学会通配符 https://blog.csdn.net/blackfwhite/article/details/80382849 --学会变量中的变量 https://www.cnblogs.co ... 
- Codeforces Round #290 (Div. 2) _B找矩形环的三种写法
			http://codeforces.com/contest/510/status/B 题目大意 给一个n*m 找有没有相同字母连起来的矩形串 第一种并查集 瞎搞一下 第一次的时候把val开成字符串了 ... 
- 欧拉函数求在1-n-1与n互质的个数
			long long phi(long long x) { long long res=x,a=x,i; ;i*i<=a;i++) { ) { res=res/i*(i-); ) a=a/i; } ... 
- postman使用--构建工作流和newman
			构建工作流 在使用“Collection Runner”的时候,集合中的请求执行顺序就是请求在Collection中的显示排列顺序.但是,有的时候我们不希望请求按照这样的方式去执行,可能是执行完第一个 ... 
- ios多线程之GCD
			介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首 ... 
- JS原型链(一)
			一.创建对象 // 第一种方式:字面量 var o1 = {name: 'o1'}; var o2 = new Object({name: 'o2'}); // 第二种方式:构造函数 var M = ... 
- 【dp】数字游戏&寒假祭
			区间DP 题目描述 丁丁最近沉迷于一个数字游戏之中.这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易.游戏是这样的,在你面前有一圈整数(一共n个),你要按 ... 
- linux中添加一个用户到指定用户组的两种方式,修改一个用户到指定用户组的一种方式
			添加一个用户到指定用户组: gpasswd –a 用户名 组名usermod –G 组名 用户名 //第一种:gpasswd –a 用户名 组名 [root@localhost ~]# id user ... 
- 【DB_MySQL】MySQL重要知识点
			MySQL中的select语句 各子句的执行顺序 SELECT语句的处理过程 1. FROM 组装数据来源 2. WHERE筛选元组 3. GROUP BY 将满足条件的元组进行分组 4. HAVIN ... 
- (3)zabbix用户管理
			登陆zabbix 默认账号:Admin,密码:zabbix,这是一个超级管理员.登陆之后在右下角可以看到“connected as Admin“(中文版:连接为Admin). zabbix组介绍 我们 ... 
