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

题目概述

给出 {qn} ,求:

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

解题报告

FFT其实是在求向量卷积,形式是这样的:

ci=j=0iajbij

然后我们观察题目里给的式子,会发现 j ij 和卷积很像啊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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值