力
推柿子。
令 \(f(i)=\frac{1}{i^2},g(i)=q_i\) 。特别地,认为 \(f(0)=0\) 。
\[E_j=\sum\limits_{i=0}^{j-1}\frac{q_i}{(i-j)^2}-\sum\limits_{i=j+1}^n\frac{q_i}{(i-j)^2}=\sum\limits_{i=0}^jf(j-i)g(i)-\sum\limits_{i=j+1}^nf(i-j)g(i)
\]
前面可以直接卷积。看一下后面。令 \(t(i)=g(n-i)\)
\[\sum\limits_{i=j+1}^nf(i-j)g(i)=\sum\limits_{i=0}^{n-j}f(i)g(i+j)=\sum\limits_{i=0}^{n-j}f(i)t(n-i-j)
\]
于是后面的也可以卷了。
另外通过这道题可以归纳出卷积的一般形式,即 \(\sum\limits_{i=0}^nA_iB_{n-i}\) 的值是A和B的卷积的第n项。这个式子最大的特点是A和B下标之和为定值,而且 \([0,i]\) 都被作为A的下标恰好一次。
code。非递归版会比递归版快三到四成。
#include<bits/stdc++.h>
//#define zczc
const int N=100010*4;
const double Pi=acos(-1.0);
using namespace std;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
wh*=f;return;
}
struct node{double a,b;}f[N],g[N],t[N];
node operator +(node s1,node s2){return (node){s1.a+s2.a,s1.b+s2.b};}
node operator -(node s1,node s2){return (node){s1.a-s2.a,s1.b-s2.b};}
node operator *(node s1,node s2){return (node){s1.a*s2.a-s1.b*s2.b,s1.a*s2.b+s1.b*s2.a};}
int m,cnt[N];
node s[N];
void FFT(node a[],int limit,int type){
for(int i=0;i<limit;i++)s[i]=a[cnt[i]];
for(int len=1;len<limit;len<<=1){
int sl=len*2;
node ww=(node){cos(2*Pi/sl),type*sin(2*Pi/sl)};
for(int l=0;l+sl<=limit;l+=sl){
node w=(node){1,0};
for(int i=0;i<len;i++,w=w*ww){
node a1=s[l+i],a2=s[l+len+i]*w;
s[l+i]=a1+a2,s[l+len+i]=a1-a2;
}
}
}
for(int i=0;i<limit;i++)a[i]=s[i];
}
signed main(){
#ifdef zczc
freopen("in.txt","r",stdin);
#endif
read(m);
for(int i=1;i<=m;i++){
scanf("%lf",&g[i].a);
t[m-i]=g[i];
f[i].a=(double)1/i/i;
}
int limit=1;while(limit<=m*2)limit<<=1;
int scnt=0;while((1<<scnt)!=limit)scnt++;
for(int i=1;i<=limit;i++)cnt[i]=(cnt[i>>1]>>1)+((i&1)<<scnt-1);
FFT(f,limit,1);FFT(g,limit,1);FFT(t,limit,1);
for(int i=0;i<limit;i++)g[i]=g[i]*f[i],t[i]=t[i]*f[i];
FFT(g,limit,-1);FFT(t,limit,-1);
for(int i=0;i<limit;i++)g[i].a/=limit,t[i].a/=limit;
for(int i=1;i<=m;i++)printf("%.3f\n",g[i].a-t[m-i].a);
return 0;
}
一如既往,万事胜意