[快速傅里叶变换--FFT]

BZOJ2179: FFT快速傅立叶

果题

BZOJ2194:请计算C[k]=sigma(a[i]*b[i-k]) 其中 k < = i < n ,并且有 n < = 10 ^ 5。 a,b中的元素均为小于等于100的非负整数。

注意到i 和 i - k有奇妙的联系

不妨尝试把b翻转

然后就变成卷积了。。


贴个模板

#include 
#define maxn 500010
using namespace std;


struct cpx{
	double r, i;
	cpx(double a=0, double b=0):r(a), i(b){}
	cpx operator+(const cpx& k)const{return cpx(r+k.r, i+k.i);}
	cpx operator-(const cpx& k)const{return cpx(r-k.r, i-k.i);}
	cpx operator*(const cpx& k)const{return cpx(r*k.r-i*k.i, r*k.i+i*k.r);}
	cpx operator/(const double& n)const{return cpx(r/n, i/n);}
}A[maxn], B[maxn], P[maxn];

int n, l, k, a[maxn], b[maxn], c[maxn], r[maxn];

int rev(int a){
	int ret = 0;
	for(int i = 0; i < l; i ++){
		ret = ret<<1|(a&1);
		a >>= 1;
	}
	return ret;
}

void Init(){
	scanf("%d", &n);k = n;
	for(int i = 0; i < n; i ++)
		scanf("%d%d", &a[i], &c[i]);
	for(int i = 0; i < n; i ++)
	    b[n-i-1] = c[i];
	for(int i = 0; i < n; i ++)
	    A[i].r = a[i], B[i].r = b[i];
	int m = n << 1;
	for(n = 1, l = 0; n <= m; n <<= 1, l ++);
	for(int i = 0; i < n; i ++)
	    r[i] = rev(i);
}
const double pi = 3.1415926535;
void FFT(cpx A[], int n, int t){
	for(int i = 0; i < n; i ++)P[r[i]] = A[i];
	for(int i = 0; i < n; i ++)A[i] = P[i];
	for(int k = 2; k <= n; k <<= 1){
		cpx wn = cpx(cos(2*pi/k), t*sin(2*pi/k));
		for(int i = 0; i < n; i += k){
			cpx w = cpx(1, 0);
			for(int j = 0; j < k>>1; j ++){
				cpx T = A[i+j+(k>>1)] * w;
				A[i+j+(k>>1)] = A[i+j] - T;
				A[i+j] = A[i+j] + T;
				w = w * wn;
			}
		}
	}
	if(t == -1)for(int i = 0; i < n; i ++)A[i] = A[i] / n;
}

int main(){
	Init();

	FFT(A, n, 1);
	FFT(B, n, 1);
	for(int i = 0; i < n; i ++)
	    A[i] = A[i] * B[i];
	FFT(A, n, -1);
	for(int i = k - 1; i < 2 * k - 1; i ++){
		int ret = A[i].r + 0.2;
		printf("%d\n", ret);
	}

	return 0;
}

你可能感兴趣的:(BZOJ,数学--FFT。NTT。FWT)