P3338 [ZJOI2014]力

传送门

看来对 FFT 的理解仍只是在表层模板而已,对问题还是不会转化


思路

我们先回顾卷积的形式:

Wk=i=0kFi×Gki

这些表示的都是系数

回到这道题,题目其实让我们求得应该是 Ei=j=1i1q[j](ij)2j=i+1nq[j](ji)2

因为这是板子题, 我们应该要将式子转化成卷积的形式

我们令 F[k]=q[k],G[k]=1k2,因此有

Ei=j=1i1F[j]G[ij]j=i+1nF[j]G[ji]

我们考虑让 F[0]=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[k]=F[nk]

Ei=j=0iF[j]G[ij]j=0niF[nij]G[j]

这时我们就成功转化了,为了让式子更好看,我们令 r=ni

Ei=j=0iF[j]G[ij]j=0rF[rj]G[j]

开卷!

令函数 A(x),B(x),C(x) 的系数表示分别为 {F[k]|0kn},{F[k]|0kn},{G[k]|0kn}

求出 X(x)=A(x)C(x), Y(x)=B(x)C(x)

最后的答案就为 Ei=XiYni


代码

#include<iostream>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#define LL long long
const int N = 2097160;
const double Pi = acos(-1);
struct Complex
{
    double a, b;
    Complex(double na = 0, double nb = 0) : a(na), b(nb) {}
    Complex operator + (const Complex &x) const {return (Complex){a + x.a, b + x.b};}
    Complex operator - (const Complex &x) const {return (Complex){a - x.a, b - x.b};}
    Complex operator * (const Complex &x) const {return (Complex){a * x.a - b * x.b, a * x.b + b * x.a};}
}A[N], B[N], C[N];
int n, m, t[N];
inline void FFT(Complex *f, bool I)
{
    for(int i = 1; i < n; i++)
        if(i < t[i]) std::swap(f[i], f[t[i]]);
    for(int now = 2, la = 1; now <= n; now <<= 1, la <<= 1)
    {
        Complex ADF(cos(2.0 * Pi / now), sin(2.0 * Pi / now));
        if(I) ADF.b = -ADF.b;
        for(int l = 0; l < n; l += now)
        {
            Complex buf(1, 0);
            for(int k = l; k < l + la; k++)
            {
                Complex mul = buf * f[k + la];
                f[k + la] = f[k] - mul;
                f[k] = f[k] + mul;
                buf = buf * ADF;
            }
        }
    }
}
signed main()
{
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
        scanf("%lf", &A[i].a), B[n - i].a = A[i].a, C[i].a = (1.0 / i / i);
    for(m = n << 1, n = 1; n <= m; n <<= 1);
    for(int i = 1; i < n; i++)
        t[i] = (t[i >> 1] >> 1) | (i & 1 ? n >> 1 : 0);
    FFT(A, 0); FFT(B, 0); FFT(C, 0);
    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);
    m >>= 1;
    for(int i = 1; i <= m; i++)
        printf("%lf\n", A[i].a / n - B[m - i].a / n);
    return 0;
}
posted @   zuytong  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示