P3338 [ZJOI2014]力
看来对 FFT
的理解仍只是在表层模板而已,对问题还是不会转化
思路
我们先回顾卷积的形式:
\[W_k=\sum_{i=0}^kF_i\times G_{k-i}
\]
这些表示的都是系数
回到这道题,题目其实让我们求得应该是 \(E_i=\sum_{j=1}^{i-1}\frac{q[j]}{(i-j)^2}-\sum_{j=i+1}^{n}\frac{q[j]}{(j-i)^2}\)
因为这是板子题, 我们应该要将式子转化成卷积的形式
我们令 \(F[k]=q[k], G[k]=\frac{1}{k^2}\),因此有
\[E_i=\sum_{j=1}^{i-1}F[j]G[i-j]-\sum_{j=i+1}^{n}F[j]G[j-i]
\]
我们考虑让 \(F[0]=G[0]=0\),让形式更靠近卷积的形式:
\[E_i=\sum_{j=0}^{i}F[j]G[i-j]-\sum_{j=i}^{n}F[j]G[j-i]
\]
右式的左半部分成功化成卷积形式了,但右边还是差点
我们考虑令 \(j=0\):
\[E_i=\sum_{j=0}^{i}F[j]G[i-j]-\sum_{j=0}^{n-i}F[j+i]G[j]
\]
我们再考虑令 \(F'[k]=F[n-k]\)
\[E_i=\sum_{j=0}^{i}F[j]G[i-j]-\sum_{j=0}^{n-i}F'[n-i-j]G[j]
\]
这时我们就成功转化了,为了让式子更好看,我们令 \(r=n-i\)
\[E_i=\sum_{j=0}^{i}F[j]G[i-j]-\sum_{j=0}^{r}F'[r-j]G[j]
\]
开卷!
令函数 \(A(x),B(x),C(x)\) 的系数表示分别为 \(\{F[k]|0\le k\le n\},\{F'[k]|0\le k\le n\},\{G[k]|0\le k\le n\}\)
求出 \(X(x)=A(x)*C(x)\), \(Y(x)=B(x)*C(x)\)
最后的答案就为 \(E_i=X_i-Y_{n-i}\)
代码
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#define LL long long
const int N = 2097160;
const double Pi = acos(-1);
struct Complex
{
double a, b;
Complex(double na = 0, double nb = 0) : a(na), b(nb) {}
Complex operator + (const Complex &x) const {return (Complex){a + x.a, b + x.b};}
Complex operator - (const Complex &x) const {return (Complex){a - x.a, b - x.b};}
Complex operator * (const Complex &x) const {return (Complex){a * x.a - b * x.b, a * x.b + b * x.a};}
}A[N], B[N], C[N];
int n, m, t[N];
inline void FFT(Complex *f, bool I)
{
for(int i = 1; i < n; i++)
if(i < t[i]) std::swap(f[i], f[t[i]]);
for(int now = 2, la = 1; now <= n; now <<= 1, la <<= 1)
{
Complex ADF(cos(2.0 * Pi / now), sin(2.0 * Pi / now));
if(I) ADF.b = -ADF.b;
for(int l = 0; l < n; l += now)
{
Complex buf(1, 0);
for(int k = l; k < l + la; k++)
{
Complex mul = buf * f[k + la];
f[k + la] = f[k] - mul;
f[k] = f[k] + mul;
buf = buf * ADF;
}
}
}
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%lf", &A[i].a), B[n - i].a = A[i].a, C[i].a = (1.0 / i / i);
for(m = n << 1, n = 1; n <= m; n <<= 1);
for(int i = 1; i < n; i++)
t[i] = (t[i >> 1] >> 1) | (i & 1 ? n >> 1 : 0);
FFT(A, 0); FFT(B, 0); FFT(C, 0);
for(int i = 0; i < n; i++)
A[i] = A[i] * C[i], B[i] = B[i] * C[i];
FFT(A, 1); FFT(B, 1);
m >>= 1;
for(int i = 1; i <= m; i++)
printf("%lf\n", A[i].a / n - B[m - i].a / n);
return 0;
}