1. 程式人生 > >洛谷P3338 [ZJOI2014]力(FFT)

洛谷P3338 [ZJOI2014]力(FFT)

wap printf algorithm href target sum mes nbsp blank

傳送門

題目要求$$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}{(j-i)^2}$$

令$x_i=\frac{1}{i^2}$,則有$$E_i=\sum_{j=1}^{i-1} q_j x_{i-j}-\sum_{j=i+1}^n q_j x_{j-i}$$

令$p_i=q_{n-i+1}$,則有$$E_i=\sum_{j=1}^{i-1} q_j x_{i-j}-\sum_{j=i+1}^n p_{n-i+1} x_{j-i}$$

那麽不難發現這兩個都是卷積(然而我連卷積是啥都不知道)

簡單來講,兩個多項式的卷積$(f*g)(n)=\sum_{i=0}^nf(i)g(n-i)$,可以發現這個和多項式乘法的某一項系數的值的求法相同

然後只要用FFT求出兩個卷積,然後做差就可以了

 1 //minamoto
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 using namespace std;
 6 const int N=3e5+5;const double Pi=acos(-1);
 7 struct complex{
 8     double
x,y; 9 complex(double xx=0,double yy=0){x=xx,y=yy;} 10 inline complex operator +(complex b){return complex(x+b.x,y+b.y);} 11 inline complex operator -(complex b){return complex(x-b.x,y-b.y);} 12 inline complex operator *(complex b){return complex(x*b.x-y*b.y,x*b.y+y*b.x);} 13 }A[N],B[N],C[N];
14 int n,m,l,r[N],limit=1; 15 void FFT(complex *A,int type){ 16 for(int i=0;i<limit;++i) 17 if(i<r[i]) swap(A[i],A[r[i]]); 18 for(int mid=1;mid<limit;mid<<=1){ 19 complex Wn(cos(Pi/mid),type*sin(Pi/mid)); 20 for(int R=mid<<1,j=0;j<limit;j+=R){ 21 complex w(1,0); 22 for(int k=0;k<mid;++k,w=w*Wn){ 23 complex x=A[j+k],y=w*A[j+mid+k]; 24 A[j+k]=x+y,A[j+mid+k]=x-y; 25 } 26 } 27 } 28 } 29 int main(){ 30 // freopen("testdata.in","r",stdin); 31 scanf("%d",&n); 32 while(limit<=n*2) limit<<=1,++l; 33 for(int i=0;i<=limit;++i) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1)); 34 for(int i=1;i<=n;++i) 35 scanf("%lf",&A[i].x),B[n+1-i].x=A[i].x,C[i].x=1.0/i/i; 36 FFT(A,1),FFT(B,1),FFT(C,1); 37 for(int i=0;i<=limit;++i) A[i]=A[i]*C[i],B[i]=B[i]*C[i]; 38 FFT(A,-1),FFT(B,-1); 39 for(int i=0;i<=limit;++i) A[i].x/=limit,B[i].x/=limit; 40 for(int i=1;i<=n;++i) 41 printf("%.3lf\n",A[i].x-B[n-i+1].x); 42 return 0; 43 }

洛谷P3338 [ZJOI2014]力(FFT)