BZOJ 3527: [Zjoi2014]力 FFT

title

BZOJ 3527

LUOGU 3338

Description

给出 \(n\) 个数 \(q_i\),给出 \(F_j\) 的定义如下:

\(F_j = \sum_{i<j}\frac{q_i q_j}{(i-j)^2 }-\sum_{i>j}\frac{q_i q_j}{(i-j)^2 }\)

\(E_i=\frac{F_i}{q_i}\),求 \(E_i\)

analysis

\[ E_j=\frac{F_j}{q_j}=\sum_{i<j}\frac{q_i}{(i-j)^2}-\sum_{i>j}\frac{q_i}{(i-j)^2} \]


\[ f[i]=q_i,g[i]=\frac{1}{i^2} \]

则原式为
\[ \sum_{i<j}f[i]g[j-i]-\sum_{i>j}f[i]g[j-i] \]


\[ \sum_{i=0}^{j-1}f[i]g[j-i]-\sum_{i=j+1}^{n}f[i]g[j-i] \]

\(f'\)\(f\) 反向后的值,则原式为
\[ \sum_{i=0}^{j-1}f[i]g[j-i]-\sum_{i=0}^{j-1}f'[i]g[j-i] \]

容易看出来这是个卷积的形式,直接 \(FFT\) 即可。

code

#include<bits/stdc++.h>

typedef long double ld;
const int maxn=5e5+10;
const ld Pi=acos(-1);

namespace IO
{
    char buf[1<<15],*fs,*ft;
    inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
    template<typename T>inline void read(T &x)
    {
        x=0;
        T f=1, ch=getchar();
        while (!isdigit(ch) && ch^'-') ch=getchar();
        if (ch=='-') f=-1, ch=getchar();
        while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
        x*=f;
    }
}

using IO::read;

struct Orz{double a,b;}A[maxn],B[maxn],C[maxn],W[maxn];
inline Orz operator + (Orz a,Orz b) { return (Orz){a.a+b.a,a.b+b.b}; }
inline Orz operator - (Orz a,Orz b) { return (Orz){a.a-b.a,a.b-b.b}; }
inline Orz operator * (Orz a,Orz b) { return (Orz){a.a*b.a-a.b*b.b,a.a*b.b+a.b*b.a}; }

int N,r[maxn],l;
inline void FFT(Orz *P,int opt)
{
    for (int i=1; i<N; ++i) if (i<r[i]) std::swap(P[i],P[r[i]]);
    for (int i=1; i<N; i<<=1)
        for (int p=i<<1,j=0; j<N; j+=p)
            for (int k=0; k<i; ++k)
            {
                Orz w=(Orz){W[N/i*k].a,W[N/i*k].b*opt};
                Orz x=P[j+k], y=w*P[j+k+i];
                P[j+k]=x+y, P[j+k+i]=x-y;
            }
    if (opt==-1)
        for (int i=0; i<N; ++i) P[i].a/=N;
}

int main()
{
    int n;read(n);
    for (N=1; N<=(n<<1); N<<=1) ++l;
    for (int i=0; i<N; ++i) r[i]=( (r[i>>1]>>1) | ((i&1)<<(l-1)) );
    for (int i=1; i<N; i<<=1)
        for (int k=0; k<i; ++k) W[N/i*k]=(Orz){cos(k*Pi/i),sin(k*Pi/i)};
    for (int i=1; i<=n; ++i) scanf("%lf",&A[i].a), B[n+1-i].a=A[i].a;
    for (int i=1; i<=n; ++i) C[i].a=(1.0/(ld)i)/(ld)i;

    FFT(A,1),FFT(B,1),FFT(C,1);
    for (int i=0; i<N; ++i) A[i]=A[i]*C[i], B[i]=B[i]*C[i];
    FFT(A,-1),FFT(B,-1);
    for (int i=1; i<=n; ++i) printf("%.3lf\n",A[i].a-B[n+1-i].a);
    return 0;
}

转载于:https://www.cnblogs.com/G-hsm/p/11412361.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值