【BZOJ3527】[Zjoi2014]力 FFT
【BZOJ3527】[Zjoi2014]力
Description
给出n个数qi,给出Fj的定义如下:
令Ei=Fi/qi,求Ei.
Input
第一行一个整数n。
接下来n行每行输入一个数,第i行表示qi。
n≤100000,0<qi<1000000000
Output
n行,第i行输出Ei。与标准答案误差不超过1e-2即可。
Sample Input
5
4006373.885184
15375036.435759
1717456.469144
8514941.004912
1410681.345880
4006373.885184
15375036.435759
1717456.469144
8514941.004912
1410681.345880
Sample Output
-16838672.693
3439.793
7509018.566
4595686.886
10903040.872
3439.793
7509018.566
4595686.886
10903040.872
题解:对于上面的式子,我们将i<j和i>j分开计算
(感觉并没有推什么)
然后上面那个本身就是一个卷积,下面那个跟快速傅里叶之二一样,反转过来也是一个卷积,用FFT算出来后相减即可
#include <iostream> #include <cmath> #include <cstdio> #include <cstring> #define pi acos(-1.0) #define z z using namespace std; struct cp { double x,y; cp (double a,double b){x=a,y=b; } cp (){} cp operator + (cp a){return cp(x+a.x,y+a.y);} cp operator - (cp a){return cp(x-a.x,y-a.y);} cp operator * (cp a){return cp(x*a.x-y*a.y,x*a.y+y*a.x);} }n1[1<<20],n2[1<<20]; double q[1<<20],a1[1<<20],a2[1<<20]; int n; void init(cp *a,int len) { int i,j,t=0; for(i=0;i<len;i++) { if(i>t) swap(a[i],a[t]); for(j=(len>>1);(t^=j)<j;j>>=1); } } void FFT(cp *a,int len,int f) { init(a,len); int i,j,k,h; cp t; for(h=2;h<=len;h<<=1) { cp wn=cp(cos(f*2*pi/h),sin(f*2*pi/h)); for(j=0;j<len;j+=h) { cp w(1,0); for(k=j;k<j+h/2;k++) t=w*a[k+h/2],a[k+h/2]=a[k]-t,a[k]=a[k]+t,w=w*wn; } } } void work(cp *a,cp *b,double *c,int len) { FFT(a,len,1),FFT(b,len,1); for(int i=0;i<len;i++) a[i]=a[i]*b[i]; FFT(a,len,-1); for(int i=0;i<len;i++) c[i]=a[i].x/len; } int main() { scanf("%d",&n); int i,j,len=1; while(len<2*n) len<<=1; for(i=0;i<n;i++) scanf("%lf",&q[i]); for(i=0;i<n;i++) n1[i]=cp(q[i],0.0),n2[i]=cp(1.0/(i+1)/(i+1),0.0); for(i=n;i<len;i++) n1[i]=cp(0.0,0.0),n2[i]=cp(0.0,0.0); work(n1,n2,a1,len); for(i=0;i<n;i++) n1[i]=cp(q[n-i-1],0.0),n2[i]=cp(1.0/(i+1)/(i+1),0.0); for(i=n;i<len;i++) n1[i]=cp(0.0,0.0),n2[i]=cp(0.0,0.0); work(n1,n2,a2,len); printf("%.3f\n",-a2[n-2]); for(i=1;i<n-1;i++) printf("%.3f\n",a1[i-1]-a2[n-i-2]); printf("%.3f\n",a1[n-2]); return 0; }
| 欢迎来原网站坐坐! >原文链接<