P3338 [ZJOI2014]力 快速傅里叶变换fft,推式子

题意

E j = ∑ i = 1 j − 1 q i ( i − j ) 2 − ∑ i = j + 1 n q i ( i − j ) 2 E_j=\sum_{i=1}^{j-1}\frac{q_i}{(i-j)^2}-\sum_{i=j+1}^{n}\frac{q_i}{(i-j)^2} Ej=i=1j1(ij)2qii=j+1n(ij)2qi

给你 q i q_i qi,求 E i E_i Ei

分析

E j = ∑ i = 1 j − 1 q i ( i − j ) 2 − ∑ i = j + 1 n q i ( i − j ) 2 E_j=\sum_{i=1}^{j-1}\frac{q_i}{(i-j)^2}-\sum_{i=j+1}^{n}\frac{q_i}{(i-j)^2} Ej=i=1j1(ij)2qii=j+1n(ij)2qi

f [ i ] = q i , g [ i ] = 1 i 2 f[i]=q_i,g[i]=\frac{1}{i^2} f[i]=qi,g[i]=i21

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

前一项已经为卷积的形式,化简第二项

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

∑ i = 0 n − j f [ j + i ] g [ i ] \sum_{i=0}^{n-j}f[j+i]g[i] i=0njf[j+i]g[i]

f ′ [ i ] = f [ n − i ] f'[i]=f[n-i] f[i]=f[ni]

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

故答案就行两项卷积相减,使用 f f t fft fft加速可得到答案。

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 1e6+10, M = N * 2, inf = 1e8;
const double PI = acos(-1);
int n, m;
int rev[N], bit, tot;
struct Complex{
    double x, y;
    Complex operator+ (const Complex& t) const { return {x + t.x, y + t.y}; }
    Complex operator- (const Complex& t) const{ return {x - t.x, y - t.y}; }
    Complex operator* (const Complex& t) const{ return {x * t.x - y * t.y, x * t.y + y * t.x}; }
}a[N], b[N], c[N];
// a[i] = j 相当于ja^i,a的i次幂前系数为j
void fft(Complex a[], int inv){
    for(int i = 0; i < tot; i++)
        if(i < rev[i]) swap(a[i], a[rev[i]]);
    for(int mid = 1; mid < tot; mid <<= 1){
        Complex w1 = Complex({cos(PI/mid), inv * sin(PI/mid)});
        for(int i = 0; i < tot; i += mid * 2){
            Complex wk = Complex({1, 0});
            for(int j = 0; j < mid; j ++, wk = wk * w1){
                Complex x = a[i + j], y = wk * a[i + j + mid];
                a[i + j] = x + y, a[i + j + mid] = x - y;
            }
        }
    }
}
int main(){
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin>>n;
    while((1 << bit) < n + n + 1) bit++; tot = 1 << bit;
    for(int i = 0; i < tot; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1));
    
    for(int i = 1; i <= n; i++) cin>>a[i].x, b[i].x = a[i].x, c[i].x = 1.0 / (double) i / (double) i;
    
    reverse(b + 1, b + n + 1);
    fft(a, 1), fft(b, 1); fft(c, 1);
    for(int i = 0; i < tot; i++) a[i] = a[i] * c[i];
    for(int i = 0; i < tot; i++) b[i] = b[i] * c[i];
    fft(a, -1); fft(b, -1);
    
    for(int i = 0; i <= n + m; i++) a[i].x = (a[i].x/tot),b[i].x = (b[i].x/tot);
    
    for(int i = 1; i <= n; i++) printf("%.6lf\n", a[i].x - b[n-i+1].x);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值