【FFT】BZOJ3527(Zjoi2014)[力]題解

題目概述

給出 {qn} ,求:

Ei=j=0i1qj(ij)2j=i+1nqj(ij)2

解題報告

FFT其實是在求向量卷積,形式是這樣的:

ci=j=0iajbij

然後我們觀察題目裏給的式子,會發現 jij 和卷積很像啊QAQ,所以構造向量:

f(i)=qi,g(i)=1i2

爲了方便,定義 g(0)=0 ,這樣的話,原式變爲:
Ei=j=0if(j)g(ij)j=inf(j)g(ji)

左邊已經是卷積的形式了,但是右邊還比較奇怪,我們先把 j 改成從 0 開始枚舉:
Ei=j=0if(j)g(ij)j=0nif(j+i)g(j)

爲了把右邊變成卷積,構造 F(i)=f(ni) ,那麼:
Ei=j=0if(j)g(ij)j=0niF(nij)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;
}
發佈了340 篇原創文章 · 獲贊 124 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章