【ZJOI2014】力

转换一下式子然后卷积就可以了

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
typedef long double ld;
struct C{
    ld x,y;
    inline C(ld a=0,ld b=0){x=a,y=b;}
    inline C operator * (const C&b)const{return C(x*b.x-y*b.y,x*b.y+y*b.x);}
    inline C operator + (const C&b)const{return C(x+b.x,y+b.y);}
    inline C operator - (const C&b)const{return C(x-b.x,y-b.y);}
    inline C operator / (const ld&b)const{return C(x/b,y/b);}
};
const int maxn = 550100;
int rev[maxn],lim;
inline void init(int len){
    lim=1;
    while(lim<len)lim<<=1;
    for(int i=1;i<lim;++i)rev[i]=rev[i>>1]>>1|(i%2*lim/2);
}
const ld pi = acosl(-1);
inline void fft(C*a,int type){
    for(int i=0;i<lim;++i)if(rev[i]>i)std::swap(a[i],a[rev[i]]);
    for(int mid=1;mid<lim;mid<<=1){
        const C W(cosl(pi/mid),(sinl(pi/mid)));
        for(int j=0;j<lim;j+=mid+mid){
            C w(1,0),*A1=a+j,*A2=a+mid+j;
            for(int k=0;k<mid;++k,++A1,++A2,w=w*W){
                const C x = *A1,y=*A2*w;
                *A1=x+y,*A2=x-y;
            }
        }
    }
    if(!type){
        for(int i=0;i<lim;++i)a[i] = a[i] / lim;
        std::reverse(a+1,a+lim);
    }
}
int n,m;
C g[maxn],q[maxn],f[maxn];
C res1[maxn],res2[maxn];
int main(){
    std::ios::sync_with_stdio(false),std::cin.tie(0);
    std::cin >> n;
    ld x;
    for(int i=1;i<=n;++i)std::cin >> x,q[i].x=x;
    for(int i=1;i<=n;++i)g[i].x=(ld)1/i/i;
    for(int i=1;i<=n;++i)f[i]=g[n+1-i];
    init(n<<1|1);
    fft(q,1),fft(g,1),fft(f,1);
    for(int i=0;i<lim;++i)res1[i]=q[i]*g[i],res2[i]=q[i]*f[i];
    fft(res1,0),fft(res2,0);
    for(int i=1;i<=n;++i)
        printf("%.18Lf
",(res1[i]-res2[n+i+1]).x);
}

  

原文地址:https://www.cnblogs.com/skip1978/p/10332535.html