【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}\]

\(1\leq i\leq n\),求 \(E_i\) 的值。

正文:

\(F_i\) 代入 \(E_i\) 得到:

\[\begin{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\n", a[i].x - c[m - i].x);
	return 0;
}
posted @ 2021-03-26 21:04  Jayun  阅读(37)  评论(0编辑  收藏  举报