默认n是2的整数幂次。f(x)=a0+a1+...+an-1,比如8,对应的bit就是3,因为只有a0a7,rev[i]是把一个数在二进制下倒过来,思想是把一个数在2进制下分为前bit-1位和最后一位的话,需要让前bit-1位倒过来,并把最后一位放到前面去,由于让rev[i>>1]倒过来会多出一个后缀0,因此需要>>1,然后把i给移动bit-1位到最前面。在实现提前把a[i]放到正确位置上的时候,要在irev[i]的时候之前到rev[i]的时候已经把原来的rev[i]的位置已经与i的位置交换了,再交换就换回来了。后面mid是枚举要合并的一半,temp中应该cos(2pi/mid2)+sin(2pi/mid2),已约分。i是枚举起始点,j是枚举左边的一半,a[i]~a[i+mid-1]储存了 (k从1到n/2)的A值,为了让a[i+j]的变化与a[i+j+mid]的变化相互独立,用x,y先储存,然后再进行操作,美其名曰蝴蝶变换...
代码:
#include<complex>
#define cp complex<double>
const double pi = acos(-1.0);
void fft(cp *a, int n, int inv)
{
int bit = 0;
while((1<<bit)<n)bit++;
for(int i = 0; i <= n-1; i++)
{
rev[i]=(rev[i>>1]>>1|((i&1)<<(bit-1)));
if(i < rev[i]) swap(a[i],a[rev[i]]);
}
for(int mid = 1; mid < n; mid*=2)
{
cp temp(cos(pi/mid),inv*sin(pi/mid));
for(int i = 0; i < n; i+=mid*2)
{
cp omega(1,0);
for(int j = 0; j < mid; j++,omega*=temp)
{
cp x = a[i+j], y = omega*a[i+j+mid];
a[i+j] = x+y, a[i+j+mid]=x-y;
}
}
}
}两个多项式a,b相乘再转系数多项式c,通常只用打这么一小段
cp a[MAXN],b[MAXN];
int c[MAXN];
fft(a,n,1),fft(b,n,1);//1系数转点值
fo(i,0,n-1)a[i]*=b[i];
fft(a,n,-1);//-1点值转系数
fo(i,0,n-1)c[i]=(int)(a[i].real()/n+0.5);//注意精度

京公网安备 11010502036488号