【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;
}