【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

Sample Output

-16838672.693
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;
}
posted @ 2017-05-19 15:12  CQzhangyu  阅读(194)  评论(0编辑  收藏  举报