题目概述
给出
{qn}
,求:
Ei=∑j=0i−1qj(i−j)2−∑j=i+1nqj(i−j)2
解题报告
FFT其实是在求向量卷积,形式是这样的:
ci=∑j=0iajbi−j
然后我们观察题目里给的式子,会发现
j
和
f(i)=qi,g(i)=1i2
为了方便,定义 g(0)=0 ,这样的话,原式变为:
Ei=∑j=0if(j)g(i−j)−∑j=inf(j)g(j−i)
左边已经是卷积的形式了,但是右边还比较奇怪,我们先把 j 改成从
Ei=∑j=0if(j)g(i−j)−∑j=0n−if(j+i)g(j)
为了把右边变成卷积,构造 F(i)=f(n−i) ,那么:
Ei=∑j=0if(j)g(i−j)−∑j=0n−iF(n−i−j)g(j)
所以用FFT求卷积,然后就可以快速得到 Ei 了。
示例程序
#include<cstdio>
#include<cmath>
#include<algorithm>
#define fr first
#define sc second
#define mp make_pair
using namespace std;
typedef double DB;typedef pair<DB,DB> C;
const int maxn=262144;const double pi=acos(-1);
int n,m,R[maxn+5];C f[maxn+5],F[maxn+5],g[maxn+5];
inline int Rev(int x,int len){
static int buf[31];for (int i=0;i<len;i++) buf[i]=x&1,x>>=1;
for (int i=0;i<len;i++) x=x<<1|buf[i];return x;
}
C operator + (const C &a,const C &b) {return mp(a.fr+b.fr,a.sc+b.sc);}
C operator - (const C &a,const C &b) {return mp(a.fr-b.fr,a.sc-b.sc);}
C operator * (const C &a,const C &b) {return mp(a.fr*b.fr-a.sc*b.sc,a.fr*b.sc+a.sc*b.fr);}
inline void FFT(C *a,int n,int f){
for (int i=0;i<n;i++) if (i<R[i]) swap(a[i],a[R[i]]);
for (int k=1;k<n;k<<=1){
C w=mp(1,0),wn=mp(cos(pi/k),sin(f*pi/k)),x,y;
for (int i=0;i<n;i+=k<<1,w=mp(1,0))
for (int j=0;j<k;j++,w=w*wn)
x=a[i+j],y=w*a[i+j+k],a[i+j]=x+y,a[i+j+k]=x-y;
}
}
int main(){
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
scanf("%d",&n);n--;for (int i=1;i<=n;i++) g[i].fr=(DB)1/i/i;
for (int i=0;i<=n;i++) scanf("%lf",&f[i].fr),F[n-i]=f[i];
m=n;int len=0;for (n=1;n<=(m<<1);n<<=1) len++;for (int i=0;i<n;i++) R[i]=Rev(i,len);
FFT(f,n,1);FFT(F,n,1);FFT(g,n,1);for (int i=0;i<n;i++) f[i]=f[i]*g[i],F[i]=F[i]*g[i];
FFT(f,n,-1);FFT(F,n,-1);for (int i=0;i<=m;i++) printf("%.3f\n",(f[i].fr-F[m-i].fr)/n);
return 0;
}