問題の意味
给出\(N \)个数\(Q_I \)、
定义
\ [F_J = \ sum_ {I = 1} ^ {J-1} \ FRAC {Q_I \回q_j} {(IJ)^ 2} - \ sum_ {I = J + 1} ^ {N} \ FRAC {Q_I \回q_j} {(IJ)^ 2} \]
\ [E_i = \ FRAC {F_iと} {Q_I} \]
求\(E_i \) (\(I \)\ [1、N]で)。
思考
まずは、共通の因子に言及簡略化することができる
\ [E_j = \ sum_ = {I} 1. 1-J ^ {} \ {Q_I FRAC} {(JI)^ 2} - \ sum_ {IがJ +を= 1。 N-} ^ {} \ {Q_I FRAC} {(JI)} ^ 2 \] (\(Q_j \)提案スワップ約)
式は、2つの部分に分けることができることに留意、二つの要因が部分に分割することができる\(I \)と\(JI \)二つの部分、すなわち、二つの部分と番号付けされている\(J \) 、その後、我々はまた、畳み込みを見つけます。
设\(F [I] = \ FRAC {1} {I ^ 2} \)、\(G [I] = Q_I \)。
则
\ [E_j = \ sum_ {i = 1} ^ {J-1} F [JI] \回G [I] - \ sum_ {I = J + 1} ^ {n}はF [JI] \回G [私] \]
このように、我々は喜んで2段階のFFTをすることができます。
下半期ことに留意すべきである(JIが\)\マイナスで、それは前方に配列全体を移動させる必要がある\(N \)前回統計答えは前方に移動する必要があります\(N \)ビット(ではありません)その後、あなたはコードを見ることができ、理解しています。
コード
#include<bits/stdc++.h>
#define _USE_MATH_DEFINES
#define ll long long
#define db double
using namespace std;
const int _=1e5+7;
const int __=3e5+7;
const db Pi=M_PI;
struct cn{
db a,b;
cn operator + (const cn &x) const {
return (cn){a+x.a,b+x.b};
}
cn operator - (const cn &x) const {
return (cn){a-x.a,b-x.b};
}
cn operator * (const cn &x) const {
return (cn){a*x.a-b*x.b,a*x.b+b*x.a};
}
};
int N,n,num[__];
db q[_],E[_];
cn f[__],g[__];
void FFT(cn *f,int id){
for(int i=0;i<n;i++)
if(i<num[i]) swap(f[i],f[num[i]]);
for(int len=2;len<=n;len<<=1){
int gap=len>>1;
cn w1=(cn){cos(2*Pi/len),sin(2*Pi/len)*id};
for(int k=0;k<n;k+=len){
cn w=(cn){1,0};
for(int i=k;i<k+gap;i++,w=w*w1){
cn tmp=w*f[i+gap];
f[i+gap]=f[i]-tmp;
f[i]=f[i]+tmp;
}
}
}
}
int main(){
//freopen("force.in","r",stdin);
cin>>N;
for(int i=1;i<=N;i++) scanf("%lf",&q[i]);
n=1; while(n<=2*N) n<<=1;
for(ll i=1;i<=N;i++){ // 这里需要开 long long
f[i].a=(db)1ll/(i*i);
g[i].a=q[i];
}
for(int i=0;i<n;i++)
num[i]=(num[i>>1]>>1)|((i&1) ?n>>1 :0);
FFT(f,1);
FFT(g,1);
for(int i=0;i<n;i++) f[i]=f[i]*g[i];
FFT(f,-1);
for(int i=1;i<=N;i++) E[i]=f[i].a/n;
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
for(ll i=0;i<=N;i++){
f[i].a=(db)1ll/((i-N)*(i-N)); // 往前移动 N 位
g[i].a=q[i];
}
f[N].a=0;
FFT(f,1);
FFT(g,1);
for(int i=0;i<n;i++) f[i]=f[i]*g[i];
FFT(f,-1);
for(int i=1;i<=N;i++) printf("%.3lf\n",E[i]-f[i+N].a/n); // 统计答案时也往前移动 N 位
return 0;
}