最近闲着无聊研究了下\(FFT\)的常数优化,大概就是各种\(3\)次变\(2or1.5\)次之类的,不过没见过啥题卡这个的吧。

关于\(FFT\)可以看这里:浅谈FFT&NTT

关于复数

设\(x=a+bi\),其中\(i\)是虚数单位,那么我们用\(\bar x\)表示\(x\)的共轭复数,即\(\bar x=a-bi\)。

共轭复数有一个这样的性质:

\[\overline{ab}=\bar a \cdot \bar b
\]

证明展开就好了,这个是下面优化的关键。

设\(\omega_n\)为\(n\)阶单位根,则\(\overline{\omega _n^{x}}=\omega_{n}^{-x}\)。

idft变dft

设\(f(x)=\sum_{i=0}^{n-1}a_ix^i\),注意到:

\[n\cdot[j]{\rm idft}(f)=\sum_{i=0}^{n-1}\omega_{n}^{-ij}a_i=a_0+\sum_{i=1}^{n-1}\omega_{n}^{ij}a_{n-i}
\]

也就是说我们如果进行一次std::reverse(a+1,a+n),然后dft(a),在除以\(n\),我们就完成了一次\(idft\)。

多项式乘法优化 1

给出多项式\(f(x)=\sum_{i=0}^{n}a_ix^i,g(x)=\sum_{i=0}^{m}b_ix^i\),求其卷积。

这里最开始介绍一种非常简洁的优化方法,构造多项式\(h(x)\):

\[h(x)=f(x)+ig(x)
\]

\[h^2(x)=f^2(x)-g^2(x)+2if(x)g(x)
\]

那么我们只需要取\(h^2(x)\)的虚部除以\(2\)就是答案,这只需要做两次\(FFT\)。

多项式乘法优化 2

这个和上面的关联不大,设\(X_i\)表示多项式\(F(x)\)\(dft\)之后的系数,\(a_i\)表示\(dft\)之前的系数,设\(F(x)\)为\(n\)项的多项式,且\(n=2^k\),注意到:

\[X_i=\sum_{j=0}^{n-1}a_j\omega_{n}^{ij},X_{n-i}=\sum_{j=0}^{n-1}a_j\omega_{n}^{-ij}
\]

即:\(X_i=\overline{X_{n-i}}\)。

这实质上是因为\(F\)没有虚部的原因,我们换一个有虚部的多项式试试:

\[X_i=\sum_{j=0}^{n-1}(a_j+ib_j)\omega_{n}^{ij}\\
X_{n-i}=\sum_{j=0}^{n-1}(a_j+ib_j)\omega_{n}^{-ij}\\
\overline{X_{n-i}}=\sum_{j=0}^{n-1}(a_j-ib_j)\omega_{n}^{ij}\\
\]

等等,我们发现第一个式子和第三个式子很像,两式相加减可以得到:

\[X_i+\overline{X_{n-i}}=2\sum_{j=0}^{n-1}a_j\omega_{n}^{ij}\\
X_i-\overline{X_{n-i}}=2i\sum_{j=0}^{n-1}b_j\omega_{n}^{ij}
\]

注意到等式右边就是\(a\) \(dft\)完之后的结果,那么对于多项式\(F(x),G(x)\),我们可以构造一个函数然后\(dft\)一次,然后\(O(n)\)得到两个多项式\(dft\)之后的结果,总共只用了一次\(FFT\)。


当然这个玩意也可以这样用:假设我们现在想求\(dft(F(x))\),我们把\(F(x)\)奇偶分类,构造多项式:

\[g(x)=\sum_{i=0}^{n/2-1}(a_{2i}+ia_{2i+1})x^i
\]

然后相当于是\(0.5\)次\(FFT\)来完成这个事,设\(dft(g(x))\)每一项为\(X_i\),\(dft(F(x))\)每一项为\(Y_i\),那么推一下可以得到:

\[Y_i=\frac{X_i+\overline{X_{n/2-i}}}{2}-2\omega_{n}^i(X_i-\overline{X_{n/2-i}})
\]

注意这里只有\(i\in [0,n/2)\)的值,\(Y_{n/2}​\)特殊处理一下,后面的可以通过前面得到。

MTT常数优化

\(\rm MTT\)就是拆系数\(\rm FFT\),设多项式\(s(x),t(x)\),我们要算\(s(x)t(x)\),模数任意。

我们拆系数,设拆完了之后是\(s(x)=a(x)+b(x)\cdot p,t(x)=c(x)+d(x)\cdot p\)。

构造\(F(x)=a(x)+i\cdot b(x)\),\(G(x)=c(x)+i\cdot d(x)\)。

那么有:

\[\begin{align}
&F(\omega_n^j)=\sum_{i=0}^{n-1}(a_i+ib_i)\omega_n^{ij}\\
&F(\omega_n^{-j})=\sum_{i=0}^{n-1}(a_i+ib_i)\omega_n^{-ij}\\
&\overline{F(\omega_n^{-j})}=\sum_{i=0}^{n-1}(a_i-ib_i)\omega_n^{ij}\\
\end{align}
\]

那么相加减可得\(a(x),b(x)\)的\(dft\)。

令\(h(x)={\rm dft}(a(x))\cdot {\rm dft}(G(x))={\rm dft}(a(x)\cdot G(x))={\rm dft}(a(x)c(x)+i\cdot a(x)d(x))\)。

那么我们\(idft\)一次\(h(x)\)就可以得到\(a(x)c(x),a(x)d(x)\)。

同理可以得到\(b(x)c(x),b(x)d(x)\),一共\(4\)次\(dft\)。

代码长这样:

void mul(int *r,int *s,int *t,int len) {
for(N=1,bit=0;N<len;N<<=1,bit++);
for(int i=1;i<N;i++) pos[i]=pos[i>>1]>>1|((i&1)<<(bit-1));
for(int i=0;i<N;i++) g[0][i]=cp(r[i]&all,r[i]>>15),g[1][i]=cp(s[i]&all,s[i]>>15);
fft(g[0]),fft(g[1]);
for(int i=0;i<N;i++) {
int j=(N-i)&(N-1);
g[2][j]=(g[0][i]+conj(g[0][j]))*cp(0.5,0)*g[1][i];
g[3][j]=(g[0][i]-conj(g[0][j]))*cp(0,-0.5)*g[1][i];
}fft(g[2]),fft(g[3]);
for(int i=0;i<N;i++) g[2][i]=g[2][i]/N,g[3][i]=g[3][i]/N;
for(int i=0;i<N;i++) {
ll pp=g[2][i].r+0.5,x=g[2][i].i+0.5,y=g[3][i].r+0.5,z=g[3][i].i+0.5;
t[i]=(pp%p+(((x+y)%p)<<15)+((z%p)<<30))%p;
}
}

FFT常数优化(共轭优化)的更多相关文章

  1. spark优化之优化数据结构

    概序: 要减少内存的消耗,除了使用高效的序列化类库以外,还有一个很重要的事情,就是优化数据结构.从而避免Java语法特性中所导致的额外内存的开销,比如基于指针的Java数据结构,以及包装类型. 有一个 ...

  2. c/c++性能优化--- cache优化的一点杂谈

    之前写了一篇关于c/c++优化的一点建议,被各种拍砖和吐槽,有赞成的有反对的,还有中立的,网友对那篇博客的的评论和吐槽,我一个都没有删掉,包括一些具有攻击性的言论.笔者有幸阅读过IBM某个项目的框架代 ...

  3. [原]Android开发优化-Adapter优化

    ListView作为Android开发中使用频率最高的一个控件,保证ListView的流畅运行,对用户体验的提高至关重要.Adapter是ListView和数据源之间的中间人,当每条数据进入可见区时, ...

  4. SqlServer 数据库引擎优化顾问优化数据库

    现在一直在做的项目,数据量相对也不小,开始的时候没有觉得,因为是刚开始,数据量还很小,在程序使用过程中速度还挺快,但是随着数据量的不停的增长,发现程序越来越慢,甚至出现了超时的问题,因此要对程序和数据 ...

  5. Mysql优化之优化工具profiling

    程序员的成长之路 2016-11-23 22:42 Mysql优化之优化工具profiling 前言 mysql优化技术: mysql优化不是做一个操作就可以的优化,它包含很多的细节,需要一点一点的优 ...

  6. QRowTable表格控件(四)-效率优化之-优化数据源

    目录 一.开心一刻 二.问题分析 三.重写数据源 1.自己存储数据 2.重写data接口 四.比较 五.相关文章 原文链接:QRowTable表格控件(四)-效率优化之-优化数据源 一.开心一刻 一程 ...

  7. 知识点整理-mysql怎么查看优化器优化后的sql

    背景 1.新建两张表 CREATE TABLE t1 (m1 )); CREATE TABLE t2 (m2 )); 2.插入些数据 INSERT INTO t1 VALUES(, , , 'c'); ...

  8. Android 性能优化 ---- 启动优化

    Android 性能优化 ---- 启动优化 1.为什么要进行启动优化 一款应用的第一印象很重要,第一印象往往决定了用户的去留.打开一款应用,如果速度很快,很顺畅,那么很容易让人觉得这款应用背后的技术 ...

  9. Android 性能优化---布局优化

    Android 性能优化---布局优化 Android 布局绘制原理 布局加载过程 setContentView() --> inflate() -- > getLayout()(I/O操 ...

随机推荐

  1. Http protocal

        https://tools.ietf.org/html/rfc2616   1. 状态码:status code 1xxx:信息--请求被接收,继续下一步处理   2xxx:成功--请求行为被 ...

  2. LintCode——颜色分类

    颜色分类:给定一个包含红,白,蓝且长度为 n 的数组,将数组元素进行分类使相同颜色的元素相邻,并按照红.白.蓝的顺序进行排序. 我们可以使用整数 0,1 和 2 分别代表红,白,蓝. 注意事项: 不能 ...

  3. MYSQL数据库与Emoji表情的故事

    问题背景 手机上众多输入法和键盘支持输入 emoji 表情,给早期设计的程序造成了越来越多的干扰. 移动端购物的流行,2018 年 "双十一"全网移动端交易达到 93.6% 微信年 ...

  4. php从入门到放弃系列-03.php函数和面向对象

    php从入门到放弃系列-03.php函数和面向对象 一.函数 php真正的威力源自它的函数,内置了1000个函数,可以参考PHP 参考手册. 自定义函数: function functionName( ...

  5. 15 Puzzle (4乘4谜题) IDA*(DFS策略与曼哈顿距离启发) 的C语言实现

    大家好!这是我的第一篇博客,由于之前没有撰写博客的经验,并且也是初入计算机和人工智能领域,可能有些表述或者理解不当,还请大家多多指教. 一.撰写目的 由于这个学期在上算法与数据结构课程的时候,其中一个 ...

  6. exit命令详解

    基础命令学习目录首页 原文链接:https://www.cnblogs.com/itcomputer/p/4157859.html 用途说明 exit命令用于退出当前shell,在shell脚本中可以 ...

  7. 互评Beta版本——可以低头,但没必要——取件帮

    基于NABCD评论作品,及改进建议 1. 根据(不限于)NABCD评论作品的选题 (1)N(Need,需求) 取件帮是一款有偿互助取件的微信小程序,很大程度上解决了学生因为距离.时间等原因无法取快递的 ...

  8. Beta版本互评

    基于NABCD评论作品,及改进建议 经过alpha发布之后,迫不及待的使用了psp daily这款软件,使用非常方便,基本的功能都可以实现,经过beta周之后,我对这款产品非常期待,希望能给我更友好的 ...

  9. OO第四阶段总结

    一.测试与正确性论证的区别 从哲学的角度来说,正确性论证与测试的关系就像理论与实践的关系一样. 使用测试的方法检验程序正确性确实是一个非常方便可行且广泛运用的方法.可以通过几个简单或复杂的测试样例,迅 ...

  10. 如何获取启动页activity

    启动页activity指App启动的第一个activity,介绍几种查看启动页activity的方法: 方法一:问开发,最有效的获取方式 方法二:dumpsys package 包名,前提是知道包名( ...