【Luogu P3338】[ZJOI2014]力

链接:

洛谷

题目大意:

给出 (n) 个数 (q_1,q_2,cdots,q_n),定义:

[F_j=sum_{i = 1}^{j - 1} frac{q_i cdot q_j}{(i - j)^2}-sum_{i = j + 1}^{n} frac{q_i cdot q_j}{(i - j)^2}\ E_i=frac{F_i}{q_i}]

(1leq ileq n),求 (E_i) 的值。

正文:

(F_i) 代入 (E_i) 得到:

[egin{aligned}E_i&=sum_{j = 1}^{i - 1} frac{q_j}{(i - j)^2}-sum_{j = i + 1}^{n} frac{q_j}{(i - j)^2}\ &=sum_{j = 1}^{i} frac{q_j}{(i - j)^2}-sum_{j = i}^{n} frac{q_j}{(i - j)^2}end{aligned}]

(f_i=q_i,g_i=frac{1}{i^2}),那么:

[E_i=sum_{j = 1}^{i} f_j cdot g_{i-j} -sum_{j = i}^{n} f_j cdot g_{j-i} ]

左边的和式已经在卷了,想办法让右边的和式也转化成卷积的形式。

可以将它转化成这样:

[sum_{j = 0}^{n-i} f_{i+j} cdot g_{j} ]

(f'_i=f_{n-i}) 得到:

[sum_{j = 0}^{n-i} f'_{n-(i+j)} cdot g_{j}=sum_{j = 0}^{n-i} f'_{n-i-j} cdot g_{j} ]

定义 (t=n-i)

[sum_{j = 0}^{t} f'_{t-j} cdot g_{j} ]

这个和式也是卷积形式了,FFT 求解了。

const int N = 200010;

const double PI = acos(-1.0);

struct Complex
{
	double x, y;
	Complex (double ix, double iy) {x = ix, y = iy;}
	Complex () {x = y = 0;}
	Complex operator + (Complex &b) 
	{
		return Complex(x + b.x, y + b.y);
	}
	Complex operator - (Complex &b) 
	{
		return Complex(x - b.x, y - b.y);
	}
	Complex operator * (Complex &b) 
	{
		return Complex(x * b.x - y * b.y, x * b.y + y * b.x);
	}
	
}a[N << 1], b[N << 1], c[N << 1];

int n, m;
int tr[N << 1];

void FFT (Complex *f, bool isDFT)
{
	for (int i = 0; i <= n; i++)
		if (i < tr[i]) swap (f[i], f[tr[i]]);
	
	for (int p = 2; p <= n; p <<= 1)
	{
		int len = p >> 1;
		Complex omega(cos(2 * PI / p), sin(2 * PI / p));
		if (!isDFT) omega.y *= -1;
		for (int k = 0; k < n; k += p)
		{
			Complex tmp(1, 0);
			for (int i = k; i < k + len; i ++)
			{
				Complex y = tmp * f[i + len];
				f[i + len] = f[i] - y;
				f[i] = f[i] + y;
				tmp = tmp * omega;
			}
		}
	}
	if(!isDFT) for (int i = 0; i < n; i++) f[i].x /= n;
}

int main()
{
	scanf ("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf ("%lf", &a[i].x),
		c[n - i].x = a[i].x, b[i].x = (double) (1.0 / i / i);
		
	for (m = n, n = 1; n <= (m << 1); n <<= 1);
	for (int i = 0; i < n; i++)
		tr[i] = (tr[i >> 1] >> 1) | (i & 1? n >> 1: 0);
	
	FFT(a, 1), FFT(b, 1), FFT(c, 1);
	
	for (int i = 0; i < n; i++) a[i] = a[i] * b[i], c[i] = c[i] * b[i];
		
	FFT(a, 0), FFT(c, 0);
	for (int i = 1; i <= m; i++)
		printf ("%.3lf
", a[i].x - c[m - i].x);
	return 0;
}
原文地址:https://www.cnblogs.com/GJY-JURUO/p/14584192.html