P3338 [ZJOI2014]力

    科技2025-11-04  10

    P3338 [ZJOI2014]力 卷积 + FFT

    题意思路Code(921ms) 传送门: https://www.luogu.com.cn/problem/P3338

    题意

    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\times q_j}{(i-j)^2}-\sum_{i=j+1}^{n}\frac{q_i\times q_j}{(i-j)^2} Fj=i=1j1(ij)2qi×qji=j+1n(ij)2qi×qj

    求 解 E i = F i q i 求解E_i=\frac{F_i}{q_i} Ei=qiFi

    思路

    首 先 来 看 看 什 么 是 卷 积 : C k = ∑ i = 0 k A i B k − i , 所 以 要 想 办 法 将 上 式 转 化 成 卷 积 的 形 式 , 然 后 F F T 加 速 求 解 。 首先来看看什么是卷积:C_k=\sum_{i=0}^kA_iB_{k-i},所以要想办法将上式转化成卷积的形式,然后FFT加速求解。 Ck=i=0kAiBkiFFT

    左 右 都 加 上 一 个 i = j 的 情 况 ( 式 子 总 体 不 变 ) 。 左右都加上一个i=j的情况(式子总体不变)。 i=j E j = F j q j = ∑ i = 1 j q i ( i − j ) 2 − ∑ i = j n q i ( i − j ) 2 E_j=\frac{F_j}{q_j}=\sum_{i=1}^{j}\frac{q_i}{(i-j)^2}-\sum_{i=j}^{n}\frac{q_i}{(i-j)^2} Ej=qjFj=i=1j(ij)2qii=jn(ij)2qi

    设 f [ i ] = q i , g [ i ] = 1 i 2 得 ( 并 且 f [ 0 ] = g [ 0 ] = 0 ) : \blue{设f[i]=q_i,g[i]=\frac{1}{i^2}得}(并且f[0]=g[0]=0): f[i]=qig[i]=i21f[0]=g[0]=0

    E j = ∑ i = 0 j f [ i ] [ j − i ] − ∑ i = j n f [ i ] g [ i − j ] E_j=\sum_{i=0}^{j}f[i][j - i]-\sum_{i=j}^{n}f[i]g[i-j] Ej=i=0jf[i][ji]i=jnf[i]g[ij]

    这 时 候 , 左 边 已 经 是 卷 积 的 形 式 了 , 所 以 就 只 要 将 右 边 转 化 一 下 即 可 。 这时候,左边 已经是卷积的形式了,所以就只要将右边转化一下即可。

    先 将 右 边 展 开 得 : 先将右边展开得:

    ∑ i = j n f [ i ] g [ i − j ] = f [ j ] g [ 0 ] + f [ j + 1 ] [ 1 ] + . . . + f [ n ] g [ n − j ] \sum_{i=j}^{n}f[i]g[i-j]=f[j]g[0]+f[j+1][1]+...+f[n]g[n-j] i=jnf[i]g[ij]=f[j]g[0]+f[j+1][1]+...+f[n]g[nj] ∑ i = j n f [ i ] g [ i − j ] = ∑ i = 0 n − j f [ i + j ] g [ i ] \sum_{i=j}^{n}f[i]g[i-j]=\sum_{i=0}^{n-j}f[i+j]g[i] i=jnf[i]g[ij]=i=0njf[i+j]g[i]

    怎 么 转 化 成 卷 积 形 式 呢 , 只 需 要 将 f 翻 转 一 下 变 成 f ′ 即 可 , 即 f ′ [ i ] = f [ n − i ] , 并 令 t = n − j , 得 下 式 : 怎么转化成卷积形式呢,只需要将f翻转一下变成f'即可,即\blue{f'[i]=f[n-i]},并令t=n-j,得下式: fff[i]=f[ni]t=nj

    ∑ i = 0 n − j f [ i + j ] g [ i ] = ∑ i = 0 t f ′ [ t − i ] g [ i ] \sum_{i=0}^{n-j}f[i+j]g[i]=\sum_{i=0}^tf'[t-i]g[i] i=0njf[i+j]g[i]=i=0tf[ti]g[i]

    合 并 一 下 , 得 下 式 : 合并一下,得下式:

    E j = ∑ i = 0 j f [ i ] [ j − i ] − ∑ i = 0 t f ′ [ t − i ] g [ i ] E_j=\sum_{i=0}^{j}f[i][j - i]-\sum_{i=0}^tf'[t-i]g[i] Ej=i=0jf[i][ji]i=0tf[ti]g[i]

    令 L ( x ) = ∑ i = 0 n f ( n ) × g ( n ) , R ( x ) = ∑ i = 0 n f ′ ( n ) × g ( n ) 令L(x)=\sum_{i=0}^nf(n)\times g(n),R(x)=\sum_{i=0}^nf'(n)\times g(n) L(x)=i=0nf(n)×g(n)R(x)=i=0nf(n)×g(n)

    则 E i = L ( i ) − R ( n − i ) 则E_i=L(i)-R(n-i) Ei=L(i)R(ni)

    先 预 处 理 f , f ′ , g , 最 后 用 F F T 加 速 卷 积 即 可 。 先预处理f,f',g,最后用FFT加速卷积即可。 f,f,gFFT

    Code(921ms)

    #include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef pair<int, int> pdd; #define INF 0x3f3f3f3f #define lowbit(x) x & (-x) #define mem(a, b) memset(a , b , sizeof(a)) #define FOR(i, x, n) for(int i = x;i <= n; i++) // const ll mod = 998244353; // const ll mod = 1e9 + 7; // const double eps = 1e-6; const double PI = acos(-1); const int N = 3e5 + 10; struct Complex { double r, i; Complex() {r == 0; i = 0;}; Complex(double real, double imag) : r(real), i(imag) {}; }A[N], B[N], C[N]; Complex operator + (Complex a, Complex b) { return Complex(a.r + b.r, a.i + b.i); } Complex operator - (Complex a, Complex b) { return Complex(a.r - b.r, a.i - b.i); } Complex operator * (Complex a, Complex b) { return Complex(a.r * b.r - a.i * b.i, a.r * b.i + a.i * b.r); } int rev[N], len, lim = 1; void FFT(Complex *a, int opt) { for(int i = 0;i < lim; i++) { if(i < rev[i]) swap(a[i], a[rev[i]]); } for(int dep = 1;dep <= log2(lim); dep++) { int m = 1 << dep; Complex wn = Complex(cos(2.0 * PI / m), opt * sin(2.0 * PI / m)); for(int k = 0;k < lim; k += m) { Complex w = Complex(1, 0); for(int j = 0;j < m / 2; j++) { Complex t = w * a[k + j + m / 2]; Complex u = a[k + j]; a[k + j] = u + t; a[k + j + m / 2] = u - t; w = w * wn; } } } if(opt == -1) { // 逆变换 for(int i = 0;i < lim; i++) a[i].r /= lim; } } void solve() { int n; scanf("%d",&n); while(lim <= (n << 1)) { lim <<= 1; len++; } for(int i = 0;i < lim; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (len - 1)); for(int i = 1;i <= n; i++) { scanf("%lf",&A[i].r); B[i].r = (double)(1.0 / i / i); C[n - i].r = A[i].r; } FFT(A, 1); FFT(B, 1); FFT(C, 1); for(int i = 0;i <= lim; i++) { A[i] = A[i] * B[i]; C[i] = C[i] * B[i]; } FFT(A, -1); FFT(C, -1); for(int i = 1;i <= n; i++) { printf("%.3lf\n",A[i].r - C[n - i].r); } } signed main() { ios_base::sync_with_stdio(false); //cin.tie(nullptr); //cout.tie(nullptr); #ifdef FZT_ACM_LOCAL freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); signed test_index_for_debug = 1; char acm_local_for_debug = 0; do { if (acm_local_for_debug == '$') exit(0); if (test_index_for_debug > 20) throw runtime_error("Check the stdin!!!"); auto start_clock_for_debug = clock(); solve(); auto end_clock_for_debug = clock(); cout << "Test " << test_index_for_debug << " successful" << endl; cerr << "Test " << test_index_for_debug++ << " Run Time: " << double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl; cout << "--------------------------------------------------" << endl; } while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug)); #else solve(); #endif return 0; }
    Processed: 0.009, SQL: 8