A * B Problem Plus
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 25113 Accepted Submission(s): 6448
Problem Description
Calculate A * B.
Input
Each line will contain two integers A and B. Process to end of file.
Note: the length of each integer will not exceed 50000.
Output
For each case, output A * B in one line.
Sample Input
1
2
1000
2
Sample Output
2
2000
题目链接:HDU 1402
题意就不说了,主要是讲下如何使用快速傅立叶变换做这入门题。
快速傅立叶变换(FFT
)可以用来快速地求两个多项式的积,就像$(1+x+2x^2)\times (3x+6x^2)=3x+6x^2+3x^2+6x^3+3x^3+6x^4=3x+9x^2+9x^3+6x^4$
输入是两个多项式的系数,输出是这两个多项式之积的系数(FFT
我一开始都不知道它是怎么用的,更不用说去学了)
那么上述的输入就是 $1\;1\;2$ 和 $0\;3\;6\;$,得到的多项式系数是$0\;3\;9\;9\;6\;0\;0\;0$(注意最低系数要补齐,从$x^0$开始,结果的次数界要为$2$的幂次)
各种介绍的博客就不说了,百度搜 FFT学习笔记
一大堆。这题如果把输入的数看成十进制下的带权求和多项式,那么就可以以多项式的乘法来得到答案的多项式表示,再把这个多项式用十进制转换成答案即可。
以$1000 \times2$为例,它就是
这两个多项式的乘积,不过不能一开始就把$10$进制这个$10$代入,应该写成
然后把结果的系数用FFT
求出来即:
再把$x=10$代入即可。
这里有几个细节问题,如果输入的多项式次数界为$a$和$b$,那么结果的次数界应该为$a+b-1$,那么FFT
时所用的$2$的幂次的次数界应该要刚好大于等于它。
又去学了下优化FFT
的姿势,把递归版改成了非递归,原理就是直接把一开始的数组按照递归合并时的顺序排序,然后就做一个类似于倍增的合并操作就行了。
学习的时候发现有几个要注意和改进的地方:
- 重复利用某一个
complex
数组的时候,在当前次数界$n$之后的复数要手动置$0$,否则答案越到后面会偏差越大 - 函数参数$f$表示正逆变换,做逆变换的时候可以把要返回的数组乘以$1 \over n$,方便一点。
- 可以预处理出所有要用的$cos(2\pi/i)$和$sin(2\pi/i)$的值,速度快一点。
FFT
函数可以写成返回一个数组的首地址,这样就可以用指针接收这个地址,方便后续进行操作(数据一大估计得delete 一下23333)ans
数组如果多次使用,其末尾也要清零,否则末尾会遗留下上次可能超过末尾的部分数字。
代码:
1 |
|