P3338 [ZJOI2014]力(FFT)

tech2022-07-15  179

题意:

给定n个实数 q i q_{i} qi,给出 F j F_{j} Fj的定义如下: F j = ∑ i < j q i q j ( i − j ) 2 − ∑ i > j q i q j ( i − j ) 2 F_{j}=\sum_{i<j}\frac {q_{i}q_{j}}{(i-j)^2}-\sum_{i>j}\frac {q_{i}q_{j}}{(i-j)^2} Fj=i<j(ij)2qiqji>j(ij)2qiqj E j = F j q j E_{j}=\frac {F_{j}}{q_{j}} Ej=qjFj,求所有 E j E_{j} Ej

要求答案误差不超过10-2

数据范围:n<=1e5,0<=q(i)<=1e9

解法:

F j = ∑ i < j q i q j ( i − j ) 2 − ∑ i > j q i q j ( i − j ) 2 F_{j}=\sum_{i<j}\frac {q_{i}q_{j}}{(i-j)^2}-\sum_{i>j}\frac {q_{i}q_{j}}{(i-j)^2} Fj=i<j(ij)2qiqji>j(ij)2qiqj

E j = F j q j E_{j}=\frac {F_{j}}{q_{j}} Ej=qjFj

消 掉 q j 得 : 消掉q_{j}得: qj:

E j = ∑ i < j q i ( i − j ) 2 − ∑ i > j q i ( i − j ) 2 E_{j}=\sum_{i<j}\frac {q_{i}}{(i-j)^2}-\sum_{i>j}\frac {q_{i}}{(i-j)^2} Ej=i<j(ij)2qii>j(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 − 1 f ( i ) ∗ g ( i − j ) − ∑ i = j + 1 n f ( i ) ∗ g ( i − j ) E_{j}=\sum_{i=1}^{j-1} f(i)*g(i-j)-\sum_{i=j+1}^{n}f(i)*g(i-j) Ej=i=1j1f(i)g(ij)i=j+1nf(i)g(ij)

因 为 当 i 在 [ 1 , j − 1 ] 范 围 内 时 , i − j < 0 , 此 时 g ( i − j ) = g ( j − i ) , 那 么 式 子 变 为 : 因为当i在[1,j-1]范围内时,i-j<0,此时g(i-j)=g(j-i),那么式子变为: i[1,j1],ij<0,g(ij)=g(ji),:

E j = ∑ i = 1 j − 1 f ( i ) ∗ g ( j − i ) − ∑ i = j + 1 n f ( i ) ∗ g ( i − j ) E_{j}=\sum_{i=1}^{j-1} f(i)*g(j-i)-\sum_{i=j+1}^{n}f(i)*g(i-j) Ej=i=1j1f(i)g(ji)i=j+1nf(i)g(ij)

左 边 ∑ i = 1 j − 1 f ( i ) ∗ g ( j − i ) 部 分 是 卷 积 形 式 , 用 F F T 计 算 左边\sum_{i=1}^{j-1} f(i)*g(j-i)部分是卷积形式,用FFT计算 i=1j1f(i)g(ji),FFT

右 边 ∑ i = j + 1 n f ( i ) ∗ g ( i − j ) 可 以 通 过 翻 转 q [ ] 数 组 变 为 : ∑ i = 1 j − 1 f ′ ( i ) ∗ g ( j − i ) , 就 变 成 卷 积 了 右边\sum_{i=j+1}^{n}f(i)*g(i-j)可以通过翻转q[]数组变为:\sum_{i=1}^{j-1}f'(i)*g(j-i),就变成卷积了 i=j+1nf(i)g(ij)q[]:i=1j1f(i)g(ji), 计 算 答 案 的 时 候 别 忘 了 再 翻 转 一 次 翻 回 来 计算答案的时候别忘了再翻转一次翻回来

code:

#include<bits/stdc++.h> using namespace std; const double P=acos(-1.0); struct CC{//复数 double x,y; CC(double xx=0,double yy=0){x=xx,y=yy;} CC operator+(const CC &a)const{return CC(x+a.x,y+a.y);} CC operator-(const CC &a)const{return CC(x-a.x,y-a.y);} CC operator*(const CC &a)const{return CC(x*a.x-y*a.y,x*a.y+y*a.x);} }; void change(CC y[],int len){ for(int i=1,j=len/2;i<len-1;i++){ if(i<j)swap(y[i],y[j]); int k=len/2; while(j>=k){ j-=k; k/=2; } if(j<k)j+=k; } } void fft(CC y[],int len,int on){//on为1或者-1,-1的时候表示逆变换 change(y,len); for(int h=2;h<=len;h<<=1){ CC wn(cos(-on*2*P/h),sin(-on*2*P/h)); for(int j=0;j<len;j+=h){ CC w(1,0); for(int k=j;k<j+h/2;k++){ CC u=y[k]; CC t=w*y[k+h/2]; y[k]=u+t; y[k+h/2]=u-t; w=w*wn; } } } if(on==-1){ for(int i=0;i<len;i++){ y[i].x/=len; } } } // const int maxm=4e5+5; CC f[maxm],ff[maxm],g[maxm]; double q[maxm],qq[maxm]; double ans[maxm]; int n; signed main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%lf",&q[i]); qq[n-i+1]=q[i]; } int len=1; while(len<n*2)len<<=1; for(int i=1;i<=n;i++){ f[i]=CC(q[i],0); ff[i]=CC(qq[i],0); g[i]=CC(1.0/i/i,0); } for(int i=n+1;i<len;i++){ f[i]=ff[i]=g[i]=CC(0,0); } fft(f,len,1); fft(ff,len,1); fft(g,len,1); for(int i=0;i<=len;i++){ f[i]=f[i]*g[i]; ff[i]=ff[i]*g[i]; } fft(f,len,-1); fft(ff,len,-1); for(int i=1;i<=n;i++){ ans[i]=f[i].x-ff[n-i+1].x; } for(int i=1;i<=n;i++){ printf("%.10f\n",ans[i]); } return 0; }
最新回复(0)