保证 是 的整幂,不会出现两边不均匀的情况(上面是有 项即 次的多项式)
设 ,将 代入上述式子(上半圆)
设 ,将 代入上述式子(下半圆)
这样在已知 和 在 的值时就可以得出 在 和 处的点值表示了
...
你并不知道这些值
又因为这个 和 也可以以同样的方式划分,所以就可以用分治搞定它
把系数表达转换为点值表达”的算法叫做DFT
#define Maxn 1350000
using namespace std;
const double Pi = acos(-1);
int n, m;
Complex f[Maxn << 1], sav[Maxn << 1];
void Dft(Complex *f, int len) {
if (len == 1)return;//边界
//指针的使用比较巧妙
Complex *fl = f, *fr = f + len / 2;
for (int k = 0; k < len; k++)sav[k] = f[k];
for (int k = 0; k < len / 2; k++)//分奇偶打乱
{
fl[k] = sav[k << 1];
fr[k] = sav[k << 1 | 1];
}
Dft(fl, len / 2);
Dft(fr, len / 2);//处理子问题
//由于每次使用的单位根次数不同(len次单位根),所以要重新求。
Complex dlt(cos(2 * Pi / len), sin(2 * Pi / len)), buf(1, 0);
for (int k = 0; k < len / 2; k++) {
//这里buf = (len次单位根的第k个)
sav[k] = fl[k] + buf * fr[k];//(1)
sav[k + len / 2] = fl[k] - buf * fr[k];//(2)
//这两条语句具体见Tips的式子
buf = buf * dlt;//得到下一个单位根。
}
for (int k = 0; k < len; k++)f[k] = sav[k];
}
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i++)scanf("%lf", &f[i].x);
//一开始都是实数,虚部为0
for (m = 1; m < n; m <<= 1);
//把长度补到2的幂,不必担心高次项的系数,因为默认为0
Dft(f, m);
for (int i = 0; i < m; ++i)
printf("(%.4f,%.4f)\n", f[i].x, f[i].y);
return 0;
}
用InverseDFT
先说结论 : 把DFT中的 换成 ,做完之后除以 即可。其中, 是 的共轭
证明:不会
code:
void IDft(Complex *f, int len) {
if (len == 1)return;
Complex *fl = f, *fr = f + len / 2;
for (int k = 0; k < len; k++)sav[k] = f[k];
for (int k = 0; k < len / 2; k++) {
fl[k] = sav[k << 1];
fr[k] = sav[k << 1 | 1];
}
IDft(fl, len / 2);
IDft(fr, len / 2);
Complex dlt(cos(2 * Pi / len), -sin(2 * Pi / len)), buf(1, 0);
for (int k = 0; k < len / 2; k++) {
sav[k] = fl[k] + buf * fr[k];//(1)
sav[k + len / 2] = fl[k] - buf * fr[k];//(2)
buf = buf * dlt;
}
for (int k = 0; k < len; k++)f[k] = sav[k];
}
但是裸的递归版能A掉板子就离谱
记录
Reference: