P3338 [ZJOI2014]力 —— FFT

mac2024-11-15  11

题目链接:点我啊╭(╯^╰)╮

题目大意:

    

解题思路:

     E i = F i q i = ∑ j = 1 i − 1 q j ( i − j ) 2 − ∑ j = i + 1 n q j ( i − j ) 2 E_i=\frac{F_i}{q_i} = \sum_{j=1}^{i-1} \frac{q_j}{(i-j)^2} - \sum_{j=i+1}^{n} \frac{q_j}{(i-j)^2} Ei=qiFi=j=1i1(ij)2qjj=i+1n(ij)2qj

    令 f i = q i f_i=q_i fi=qi g i = 1 i 2 g_i=\frac{1}{i^2} gi=i21 p i = q n − i + 1 p_i=q_{n-i+1} pi=qni+1

     E i = ∑ j = 1 i − 1 f j g i − j − ∑ j = i + 1 n q j g i − j = ∑ j = 1 i − 1 f j g i − j − ∑ j = 1 i − 1 p j g j − i E_i = \sum_{j=1}^{i-1} f_j g_{i-j} - \sum_{j=i+1}^{n} q_{j} g_{i-j} = \sum_{j=1}^{i-1} f_j g_{i-j} - \sum_{j=1}^{i-1} p_{j} g_{j-i} Ei=j=1i1fjgijj=i+1nqjgij=j=1i1fjgijj=1i1pjgji

    两边都是卷积的形式,FFT即可

核心:卷积形式的变换

#include<bits/stdc++.h> #define rint register int #define deb(x) cerr<<#x<<" = "<<(x)<<'\n'; using namespace std; typedef long long ll; const int maxn = 2e5 + 5; const double pi = acos(-1); int n, len, rev[maxn<<1]; struct cp { double x, y; cp(double _x=0, double _y=0) {x = _x, y = _y;} cp operator + (const cp &A) const {return cp(x+A.x, y+A.y);} cp operator - (const cp &A) const {return cp(x-A.x, y-A.y);} cp operator * (const cp &A) const {return cp(x*A.x-y*A.y, x*A.y+y*A.x);} } f[maxn<<1], p[maxn<<1], g[maxn<<1]; void fft(cp *f, int inv) { for(int i=0; i<len; i++) if(i<rev[i]) swap(f[i], f[rev[i]]); for(int p=2; p<=len; p<<=1) { // 区间长度 int Len = p >> 1; // 待合并长度 cp wn(cos(2*pi/p), inv*sin(2*pi/p)); for(int k=0; k<len; k+=p) { // 起始点 cp w(1, 0); for(int i=k; i<k+Len; i++) { cp tmp = w * f[i+Len]; f[i+Len] = f[i] - tmp; f[i] = f[i] + tmp; w = w * wn; } } } } int main() { scanf("%d", &n); for(int i=1; i<=n; i++) { scanf("%lf", &f[i].x); p[i].x = f[i].x; g[i].x = 1.0 / double(i) / double(i); } reverse(p+1, p+1+n); for(len=1; len<=n+n; len<<=1); for(int i=0; i<len; i++) rev[i] = (rev[i>>1]>>1) | ((i&1) ? len>>1 : 0); fft(f, 1), fft(p, 1), fft(g, 1); for(int i=0; i<len; i++) f[i] = f[i] * g[i], p[i] = p[i] * g[i]; fft(f, -1), fft(p, -1); for(int i=1; i<=n; i++) f[i].x /= len, p[i].x /= len; for(int i=1; i<=n; i++) printf("%.3f\n", f[i].x - p[n-i+1].x); }
最新回复(0)