P3338 [ZJOI2014] FFT

题意

传送门 P3338 [ZJOI2014]力

题解

对于左右两项,分别令 k = j − i , k = i − j k = j - i, k = i - j k=ji,k=ij
E j = ∑ k = 1 j − 1 q j − k k 2 − ∑ k = 1 n − j q j + k k 2 E_j = \sum\limits_{k=1}^{j-1}\frac{q_{j-k}}{k^2} - \sum\limits_{k=1}^{n-j}\frac{q_{j+k}}{k^2} Ej=k=1j1k2qjkk=1njk2qj+k g k = 1 / k 2 , f k = q k g_k = 1/k^2, f_k = q_k gk=1/k2,fk=qk,上式转换为
∑ g k f i [ k + i = j ] + ∑ g k f k + j \sum g_kf_i[k+i=j] + \sum g_kf_{k+j} gkfi[k+i=j]+gkfk+j 左右两项都化为卷积的形式,FFT 求解即可。总时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

#include <bits/stdc++.h>
using namespace std;
using cp = complex<double>;
constexpr double PI = acos(-1);
vector<int> rev;
struct Poly : vector<cp>
{
    Poly() {}
    Poly(int n) : vector<cp>(n) {}
    Poly(const initializer_list<cp> &list) : vector<cp>(list) {}
    void fft(int n, bool inverse)
    {
        if ((int)rev.size() != n)
        {
            rev.resize(n);
            for (int i = 0; i < n; ++i)
                rev[i] = rev[i >> 1] >> 1 | (i & 1 ? n >> 1 : 0);
        }
        resize(n);
        for (int i = 0; i < n; ++i)
            if (i < rev[i])
                std::swap(at(i), at(rev[i]));

        for (int m = 1; m < n; m <<= 1)
        {
            int m2 = m << 1;
            cp _w = cp(cos(2 * PI / m2), sin(2 * PI / m2));
            if (inverse)
                _w = conj(_w);
            for (int i = 0; i < n; i += m2)
            {
                cp w = cp(1, 0);
                for (int j = 0; j < m; ++j, w *= _w)
                {
                    cp &x = at(i + j), &y = at(i + j + m);
                    cp t = w * y;
                    y = x - t;
                    x += t;
                }
            }
        }
    }
    void dft(int n) { fft(n, 0); };
    void idft(int n)
    {
        fft(n, 1);
        for (int i = 0; i < n; ++i)
            at(i) /= n;
    }
    Poly operator*(const Poly &p) const
    {
        auto a = *this, b = p;
        int k = 1, n = a.size() + b.size() - 1;
        while (k < n)
            k <<= 1;
        a.dft(k), b.dft(k);
        for (int i = 0; i < k; ++i)
            a[i] *= b[i];
        a.idft(k);
        a.resize(n);
        return a;
    }
};
constexpr int MAXN = 1E5 + 5;
int N;
double F[MAXN], G[MAXN], E[MAXN];

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> N;
    for (int i = 1; i <= N; ++i)
        cin >> F[i];
    for (int i = 1; i <= N; ++i)
        G[i] = 1 / ((double)i * i);
    Poly g(N + 1), f(N + 1);
    for (int i = 0; i <= N; ++i)
        g[i].real(G[i]), f[i].real(F[i]);
    f = f * g;
    for (int i = 1; i <= N; ++i)
        E[i] += f[i].real();
    for (int i = 0; i <= N; ++i)
        g[i].real(G[i]), f[i].real(F[N - i]);
    f = f * g;
    for (int i = 1; i <= N; ++i)
        E[i] -= f[N - i].real();
    for (int i = 1; i <= N; ++i)
        cout << fixed << setprecision(3) << E[i] << '\n';
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值