快速傅里叶变换(FFT)

板子

const int N = 4e5 + 10;
const double PI = acos(-1.0);
struct Complex{
	double x, y;
	Complex (){}
	Complex (double u, double v){	x = u, y = v;}
	Complex operator + (const Complex & other) const{ return Complex (x + other.x, y + other.y);}
	Complex operator - (const Complex & other) const{ return Complex (x - other.x, y - other.y);}
	Complex operator * (const Complex & other) const{ return Complex(x * other.x - y * other.y, x * other.y + y * other.x);}
	
}A[N], B[N];
int rev[N];
int FFT_pre(int n) //n = |A|+|B|
{
	int lim = 1, L = 0;
	while(lim <= n)	lim <<= 1, L++;
	for(int i = 0; i < lim; i++)	
		rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (L - 1));
	return lim;
}
void FFT(Complex a[], int lim, int opt)
{
	for(int i = 0; i < lim; i++)
		if(i < rev[i])
			swap(a[i], a[rev[i]]);
	for(int i = 2; i <= lim; i <<= 1)
	{
		int tmp = i >> 1;
		Complex wn = Complex(cos(2 * PI / i), opt * sin(2 * PI / i));
		for(int j = 0; j < lim; j += i)
		{
			Complex w = Complex(1.0, 0.0);
			for(int k = 0; k < tmp; k++)
			{
				Complex tmp1 = a[j + k];
				Complex tmp2 = w * a[j + k + tmp];
				a[j + k] = tmp1 + tmp2;
				a[j + k + tmp] = tmp1 - tmp2;
				w = w *wn;
			}
		}
	}
	if(opt == -1)
		for(int i = 0; i < lim; i++)
			a[i].x /= lim;
}

题目

[ZJOI2014]力

题意:给电荷量,求场强。即给 q j q_{j} qj F j = ∑ i = 1 j − 1 q i ∗ q j ( i − j ) 2 − ∑ i = j + 1 n q i ∗ q j ( i − j ) 2 F_{j}=\sum_{i = 1}^{j-1}\frac{q_{i}*q_{j}}{(i-j)^{2}}-\sum_{i = j+1}^{n}\frac{q_{i}*q_{j}}{(i-j)^{2}} Fj=i=1j1(ij)2qiqji=j+1n(ij)2qiqj, E j = F j q j E_{j}=\frac{F_{j}}{q_{j}} Ej=qjFj,求 E j E_{j} Ej
思路 E j = ∑ i = 1 j − 1 q i ( i − j ) 2 − ∑ i = j + 1 n q i ( i − j ) 2 E_{j}=\sum_{i = 1}^{j-1}\frac{q_{i}}{(i-j)^{2}}-\sum_{i = j+1}^{n}\frac{q_{i}}{(i-j)^{2}} Ej=i=1j1(ij)2qii=j+1n(ij)2qi
左边加一个j,右边减一个j,
= ∑ i = 1 j q i ( i − j ) 2 − ∑ i = j n q i ( i − j ) 2 =\sum_{i = 1}^{j}\frac{q_{i}}{(i-j)^{2}}-\sum_{i = j}^{n}\frac{q_{i}}{(i-j)^{2}} =i=1j(ij)2qii=jn(ij)2qi
q 0 = 0 q_{0}=0 q0=0
= ∑ i = 0 j q i ( i − j ) 2 − ∑ i = j n q i ( i − j ) 2 =\sum_{i = 0}^{j}\frac{q_{i}}{(i-j)^{2}}-\sum_{i = j}^{n}\frac{q_{i}}{(i-j)^{2}} =i=0j(ij)2qii=jn(ij)2qi
k = i − j k=i-j k=ij
= ∑ i = 0 j q i ( i − j ) 2 − ∑ k = 0 n − j q k + j k 2 =\sum_{i = 0}^{j}\frac{q_{i}}{(i-j)^{2}}-\sum_{k = 0}^{n-j}\frac{q_{k+j}}{k^{2}} =i=0j(ij)2qik=0njk2qk+j
翻转q,令 Q i = q n − i Q_{i} = q_{n-i} Qi=qni,则 q k + j = Q ( n − j ) − i q_{k+j}=Q_{(n-j)-i} qk+j=Q(nj)i
= ∑ i = 0 j q i ( i − j ) 2 − ∑ k = 0 n − j Q ( n − j ) − i k 2 =\sum_{i = 0}^{j}\frac{q_{i}}{(i-j)^{2}}-\sum_{k = 0}^{n-j}\frac{Q_{(n-j)-i}}{k^{2}} =i=0j(ij)2qik=0njk2Q(nj)i
卷就完事了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int N = 4e5 + 10;
const double PI = acos(-1.0);
struct Complex{
	double x, y;
	Complex (){}
	Complex (double u, double v){	x = u, y = v;}
	Complex operator + (const Complex & other) const{ return Complex (x + other.x, y + other.y);}
	Complex operator - (const Complex & other) const{ return Complex (x - other.x, y - other.y);}
	Complex operator * (const Complex & other) const{ return Complex(x * other.x - y * other.y, x * other.y + y * other.x);}
	
}a[N], b[N], c[N];
int rev[N];
void FFT(Complex a[], int lim, int opt)
{
	for(int i = 0; i < lim; i++)
		if(i < rev[i])
			swap(a[i], a[rev[i]]);
	for(int i = 2; i <= lim; i <<= 1)
	{
		int tmp = i >> 1;
		Complex wn = Complex(cos(2 * PI / i), opt * sin(2 * PI / i));
		for(int j = 0; j < lim; j += i)
		{
			Complex w = Complex(1.0, 0.0);
			for(int k = 0; k < tmp; k++)
			{
				Complex tmp1 = a[j + k];
				Complex tmp2 = w * a[j + k + tmp];
				a[j + k] = tmp1 + tmp2;
				a[j + k + tmp] = tmp1 - tmp2;
				w = w *wn;
			}
		}
	}
	if(opt == -1)
		for(int i = 0; i < lim; i++)
			a[i].x /= lim;
}
int main()
{
	int n;
	scanf("%d", &n);
	for(int i = 1; i <= n; i++)
		scanf("%lf", &a[i].x);
	for(int i = 1; i <= n; i++)
	{
		b[i].x = (double)(1.0 / i / i);
		c[n - i].x = a[i].x;
	}
	int lim = 1, L = 0;
	while(lim <= (n << 1))	lim <<= 1, L++;
	for(int i = 0; i < lim; i++)	
		rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (L - 1));
	FFT(a, lim,1), FFT(b, lim, 1),FFT(c, lim, 1);
	for(int i = 0; i < lim; i++)	
		a[i] = a[i] * b[i], c[i] = c[i] * b[i];
	FFT(a, lim, -1), FFT(c, lim, -1);
	for(int i = 1; i <= n; i++)
		printf("%.3lf\n", a[i].x - c[n - i].x);
	return 0;
}
[AH2017/HNOI2017]礼物

题意:数组 a i a_{i} ai b i b_{i} bi,可以对 a i a_{i} ai整体加一个正整数,也可以对 b i b_{i} bi整体加一个正整数,然后进行轮转,求 ∑ i = 1 n ( a i − b i ) 2 \sum_{i=1}^{n}(a_{i}-b_{i})^{2} i=1n(aibi)2 的最小值。
思路
  整体加值的操作可以看出在其中一个数组上进行加减,于是所求值可以写成 ∑ i = 1 n ( a i + x − b i ) 2 = ∑ i = 1 n a i 2 + ∑ i = 1 n b i 2 + n x 2 + 2 x ∑ i = 1 n a i − 2 x ∑ i = 1 2 b i − 2 ∑ i = 1 n a i b i \sum_{ i=1}^{n}(a_{i}+x-b_{i})^{2}=\sum_{i=1}^{n}a_{i}^{2}+\sum_{i=1}^{n}b_{i}^{2}+nx^{2}+2x\sum_{i=1}^{n}a_{i}-2x\sum_{i=1}^{2}b_{i}-2\sum_{i=1}^{n}a_{i}b_{i} i=1n(ai+xbi)2=i=1nai2+i=1nbi2+nx2+2xi=1nai2xi=12bi2i=1naibi。发现只需求 n x 2 − 2 ∑ i = 1 n a i b i nx^{2}-2\sum_{i=1}^{n}a_{i}b_{i} nx22i=1naibi的最小值就可以了,而 n x 2 nx^{2} nx2 2 ∑ i = 1 n a i b i 2\sum_{i=1}^{n}a_{i}b_{i} 2i=1naibi两项的变化没有关系,可以分开来看。
  对于 ∑ i = 1 n a i b i \sum_{i=1}^{n}a_{i}b_{i} i=1naibi翻转 a i a_{i} ai得到 ∑ i = 1 n a n − i b i \sum_{i=1}^{n}a_{n-i}b_{i} i=1nanibi,倍长 b i b_{i} bi以后FFT,求 x n x^{n} xn项以后最小的即可。
  对于 n x 2 nx^{2} nx2,枚举[-m, m]中每一个值就可以了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int N = 4e5 + 10;
const double PI = acos(-1.0);
struct Complex{
	double x, y;
	Complex (){}
	Complex (double u, double v){	x = u, y = v;}
	Complex operator + (const Complex & other) const{ return Complex (x + other.x, y + other.y);}
	Complex operator - (const Complex & other) const{ return Complex (x - other.x, y - other.y);}
	Complex operator * (const Complex & other) const{ return Complex(x * other.x - y * other.y, x * other.y + y * other.x);}
	
}A[N], B[N];
int rev[N];
int FFT_pre(int n)
{
	int lim = 1, L = 0;
	while(lim <= n)	lim <<= 1, L++;
	for(int i = 0; i < lim; i++)	
		rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (L - 1));
	return lim;
}
void FFT(Complex a[], int lim, int opt)
{
	for(int i = 0; i < lim; i++)
		if(i < rev[i])
			swap(a[i], a[rev[i]]);
	for(int i = 2; i <= lim; i <<= 1)
	{
		int tmp = i >> 1;
		Complex wn = Complex(cos(2 * PI / i), opt * sin(2 * PI / i));
		for(int j = 0; j < lim; j += i)
		{
			Complex w = Complex(1.0, 0.0);
			for(int k = 0; k < tmp; k++)
			{
				Complex tmp1 = a[j + k];
				Complex tmp2 = w * a[j + k + tmp];
				a[j + k] = tmp1 + tmp2;
				a[j + k + tmp] = tmp1 - tmp2;
				w = w *wn;
			}
		}
	}
	if(opt == -1)
		for(int i = 0; i < lim; i++)
			a[i].x /= lim;
}
int a[N], b[N];
int main()
{
	int n, m;
	scanf("%d%d", &n, &m);
	for(int i = 1;i <= n; i++)	scanf("%d", &a[i]);
	for(int i = 1; i <= n; i++)	scanf("%d", &b[i]);
	LL sum1 = 0, sum2 = 0;
	for(int i = 1; i <= n; i++)
	{
		A[n - i + 1].x = a[i];
		B[i].x = B[i + n].x = b[i];
		sum1 += a[i] * a[i] + b[i] * b[i];
		sum2 += a[i] - b[i];
	}
	int lim = FFT_pre(n * 3);
	FFT(A, lim, 1);
	FFT(B, lim, 1);
	for(int i = 0; i < lim; i++)	A[i] = A[i] * B[i];
	FFT(A, lim, -1);
	LL ans = 1e18;
	for(int i = 1; i <= n; i++)
		for(int j = -m; j <= m; j++)
			ans = min(ans, sum1 + 2 * j * sum2 + n * j * j - 2 * (LL)(A[i + n].x + 0.5));
	cout << ans;
	return 0; 
 } 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值