[ZJOI2014]力(FFT)

[Luogu3338] [BZOJ5327] (DarkBZOJ数据有问题)


\(19.3.8\)

前置知识:[知乎-如何通俗易懂地解释卷积] [FFT详解]

\(1.\)卷积定义

我们称 \((f*g)(n)\) 为$ f,g$ 的卷积

其连续的定义为:

\(\displaystyle (f*g)(n)=\int _{-\infty }^{\infty }f(\tau )g(n-\tau )d\tau \\\)

其离散的定义为:

\(\displaystyle (f*g)(n)=\sum _{\tau =-\infty }^{\infty }{f(\tau )g(n-\tau )}\\\)

本题题解:推式子

\(2.\)推式子原则\(:\)枚举\(j,\)则把多余的变量\(i\)消掉

这里比较巧妙的转化:\(0\le j \le n-i \ <==> \ 0 \le n-i-j \le n-i\)

\(3.\)FFT模板


\(19.4.3\)

根本不用那么麻烦 , 直接把数组反过来就行了 ...

更新于\(19.4.3\)代码

// luogu-judger-enable-o2
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define Debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
typedef long long LL;
const int INF=1e9+7;
inline LL read(){
    register LL x=0,f=1;register char c=getchar();
    while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
    while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
    return f*x;
}

const int MAXN=3e5+5;//开3倍空间
const double Pi=acos(-1);

namespace F_F_T{

    struct cmpx{
        double x,y;
        cmpx(double xx=0,double yy=0){x=xx,y=yy;}
        inline friend cmpx operator + (cmpx a,cmpx b){return cmpx(a.x+b.x,a.y+b.y);}
        inline friend cmpx operator - (cmpx a,cmpx b){return cmpx(a.x-b.x,a.y-b.y);}
        inline friend cmpx operator * (cmpx a,cmpx b){return cmpx(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
    }A[MAXN],B[MAXN],C[MAXN];

    int r[MAXN],limit=1,l;

    inline void FFT(cmpx *A,int type){
        for(int i=0;i<limit;i++)
            if(i<r[i]) swap(A[i],A[r[i]]);
        for(int len=1;len<limit;len<<=1){
            cmpx Wn=(cmpx){cos(Pi/len),type*sin(Pi/len)};
            for(int j=0;j<limit;j+=(len<<1)){
                cmpx w=(cmpx){1,0};
                for(int k=0;k<len;k++,w=w*Wn){
                    cmpx x=A[j+k],y=w*A[j+len+k];
                    A[j+k]=x+y;
                    A[j+len+k]=x-y;
                }
            }
        }
    }

}using namespace F_F_T;

int n;

int main(){
    n=read();
    for(int i=1;i<=n;i++){
        scanf("%lf",&A[i].x);//long double 对应的是 %Lf
        B[n-i].x=A[i].x;
        C[i].x=(double)1/i/i;
    }
    while(limit<=n*2) limit<<=1,l++;
    for(int i=0;i<limit;i++)
        r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    FFT(A,1);
    FFT(B,1);
    FFT(C,1);
    for(int i=0;i<limit;i++)
        A[i]=A[i]*C[i],B[i]=B[i]*C[i];
    FFT(A,-1);
    FFT(B,-1);
    for(int i=0;i<limit;i++)//所有的都不要取到=
        A[i].x/=limit,B[i].x/=limit;
    for(int i=1;i<=n;i++)
        printf("%.5lf\n",A[i].x-B[n-i].x);
}

转载于:https://www.cnblogs.com/lizehon/p/10498194.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值