您的位置:首页 > 其它

BZOJ3527 力

2016-06-20 16:13 162 查看
题目链接

题目大意

BZOJ讨论版里有pdf.

给出n个数qi,给出Fj的定义如下:

Fj=∑i<jqiqj(i−j)2−∑i>jqiqj(i−j)2.

对所有j,求Ej=Fjqj.

题解

这道ZJOI2014的题感觉完全比不上上一道FFT构造题啊…

为了方便令qi下标从0开始,可以把Ej化简成这样:

Ej=∑i=0j−1qi(i−j)2−∑i=j+1n−1qi(i−j)2.

考虑怎么求前面那个和式,后面的那个和式可以把qi数组倒过来用相同的方法求.

怎么求?构造多项式!

注意到两个多项式相乘得到的系数是这样的:

ck=∑i=0kaibk−i.

然后很容易构造出多项式A,B,系数为ai=qi,bi=1(i+1)2,它们相乘得到的多项式第j−1项的系数即为∑j−1i=0qi(i−j)2.

然后这题套个FFT就没了.

时间复杂度O(nlgn).

代码

#include<cstdio>
#include<cmath>
#include<complex>
#include<algorithm>
using namespace std;
typedef complex<double> C;
const int N=1e5+5,M=(1<<18)+5;
const double pi=acos(-1.0);
int rev[M];
C A[M],B[M],ans[2][M];
void FFT(C *arr,int n,int flag){
for(int i=0;i<n;++i)
if(i<rev[i])
swap(arr[i],arr[rev[i]]);
for(int m=2;m<=n;m<<=1){
C wm(cos(2*pi/m),flag*sin(2*pi/m));
for(int i=0;i<n;i+=m){
C w(1,0);
for(int j=0;j<m>>1;++j,w*=wm){
C x=arr[i+j],y=w*arr[i+j+(m>>1)];
arr[i+j]=x+y;
arr[i+j+(m>>1)]=x-y;
}
}
}
}
void calc_FFT(int n,bool id){
int _n=n,m=n<<1,S=0;
for(n=1;n<=m;n<<=1,++S);
rev[0]=0;
for(int i=1;i<n;++i)
rev[i]=(rev[i>>1]>>1)|((i&1)<<S-1);
for(int i=_n+1;i<n;++i)
A[i]=B[i]=0;
FFT(A,n,1);
FFT(B,n,1);
for(int i=0;i<n;++i)
ans[id][i]=A[i]*B[i];
FFT(ans[id],n,-1);
for(int i=0;i<m;++i)
ans[id][i]/=n;
}
double num
;
int main(){
int n;
scanf("%d",&n);
for(int i=0;i<n;++i)
scanf("%lf",&num[i]);
for(int i=0;i<n;++i){
A[i]=num[i];
B[i]=1.0/(i+1)/(i+1);
}
calc_FFT(n-1,0);
for(int i=0;i<n-1-i;++i)
swap(num[i],num[n-1-i]);
for(int i=0;i<n;++i){
A[i]=num[i];
B[i]=1.0/(i+1)/(i+1);
}
calc_FFT(n-1,1);
for(int i=n-1;i;--i){
ans[0][i]=ans[0][i-1];
ans[1][i]=ans[1][i-1];
}
ans[0][0]=ans[1][0]=0;
for(int i=0;i<n-1-i;++i)
swap(ans[1][i],ans[1][n-1-i]);
for(int i=0;i<n;++i)
printf("%f\n",(ans[0][i]-ans[1][i]).real());
return 0;
}
/*

Jun.20.16

Tags:FFT
Submissions:1

Memory 19000kb
Time 8356ms
Code Length 1639B

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bzoj fft