BZOJ3527: [Zjoi2014]力【FFT】

3527: [Zjoi2014]力

先除去qiq_i,令g(i)=1i2g(i)=\frac{1}{i^2}式子变成Ei=j=1i1qig(ij)j=i+1nqig(ji)E_i=\sum_{j=1}^{i-1} q_i*g(i-j)-\sum_{j=i+1}^nq_i*g(j-i)

然后将后一半翻转Ei=j=1i1qig(ij)j=1niqnig(ji)E_i=\sum_{j=1}^{i-1} q_i*g(i-j)-\sum_{j=1}^{n-i}q_{n-i}*g(j-i)

就是两个卷积相减辣,直接FFT

#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=200005;
const double PI=acos(-1.0);
int n,Len,lg2,rev[MAXN<<1];
struct CP{
	double x,y;
	CP(double X=0,double Y=0){x=X,y=Y;}
	CP operator +(const CP b)const{return CP(x+b.x,y+b.y);}
	CP operator -(const CP b)const{return CP(x-b.x,y-b.y);}
	CP operator *(const CP b)const{return CP(x*b.x-y*b.y,x*b.y+y*b.x);} 
};
CP G[MAXN<<1],B1[MAXN<<1],B2[MAXN<<1],Ans1[MAXN<<1],Ans2[MAXN<<1];
void FFT(CP *A,int opt){
	for(int i=0;i<Len;i++) if(rev[i]<i) swap(A[i],A[rev[i]]);
	for(int i=1;i<Len;i<<=1){
		CP WN(cos(PI/i),opt*sin(PI/i));
		for(int j=0;j<Len;j+=i<<1){
			CP WNK(1,0);
			for(int k=0;k<i;k++,WNK=WN*WNK){
				CP x=A[j+k],y=WNK*A[j+k+i];
				A[j+k]=x+y;A[j+k+i]=x-y; 
			}
		}
	}
	if(opt==-1) for(int i=0;i<Len;i++) A[i].x/=Len;
}
void Getrev(){for(int i=0;i<Len;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg2-1));}
int main(){
	scanf("%d",&n);n--;
	for(int i=0;i<=n;i++) scanf("%lf",&B1[i].x),B2[n-i].x=B1[i].x;
	for(int i=1;i<=n;i++) G[i].x=1.0/i/i;
	for(Len=1,lg2=0;Len<=n<<1;Len<<=1,lg2++);Getrev();
	FFT(G,1),FFT(B1,1),FFT(B2,1);
	for(int i=0;i<Len;i++) Ans1[i]=G[i]*B1[i];
	for(int i=0;i<Len;i++) Ans2[i]=G[i]*B2[i];
	FFT(Ans1,-1),FFT(Ans2,-1);
	for(int i=0;i<=n;i++) printf("%.8lf\n",Ans1[i].x-Ans2[n-i].x);
	return 0;
} 
posted @ 2019-03-17 16:20  XSamsara  阅读(115)  评论(0编辑  收藏  举报