1. 程式人生 > >Luogu 4705 玩遊戲

Luogu 4705 玩遊戲

max 每一個 多項式 -a ans getc include online lap

看見這個題依稀想起了$5$月月賽時候的事情,到現在仍然它感覺非常神仙。

遊戲$k$次價值的期望答案

$$ans_k = \frac{1}{nm}\sum_{i = 1}^{n}\sum_{j = 1}^{n}(a_i + b_j)^k$$

二項式定理展開

$$ans_k=\frac{1}{nm}\sum_{i = 1}^{n}\sum_{j = 1}^{m}\sum_{t = 0}^{k}\binom{k}{t}a_i^tb_j^{k - t}$$

$$ = \frac{1}{nm}\sum_{t = 0}^{k}\binom{k}{t}\sum_{i = 1}^{n}a_i^t\sum_{j = 1}^{m}b_j^{k - t}$$

$$= \frac{k!}{nm}\frac{\sum_{i = 1}^{n}a_i^t}{t!}\frac{\sum_{j = 1}^{m}b_j^{k - t}}{(k - t)!}$$

容易發現這後面是一個卷積的形式。

我們設$A(x) = \frac{\sum_{i = 1}^{n}a_i^x}{x!}$,$B(x) = \frac{\sum_{i = 1}^{n}b_i^x}{x!}$,答案就變成了

$$\frac{k!}{nm}(A * B)(k)$$

現在考慮怎麽算這個$\sum_{i = 1}^{n}a_i^k$。

不會了,點開題解

我們構造一個多項式$F(x) = \prod_{i = 1}^{n}(1 - a_ix)$,這個$F(x)$可以通過分治算出來,時間復雜度$T(n) = 2T(\frac{n}{2}) + O(nlogn)$趨向$O(nlogn)$???。

接下來要開始變魔術了,

設$G(x) = lnF(x)$,

$$G(x) = \sum_{i = 1}^{n}ln(1 - a_ix)$$

對裏面的$ln$在$x_0 = 0$處泰勒展開。

我們知道

$$ln(1 - x) = 0 - \frac{x}{1} - \frac{x^2}{2} - \frac{x^3}{3} - \cdots = -\sum_{i = 1}^{\infty}\frac{x^i}{i}$$

所以

$$G(x) = \sum_{i = 1}^{n}\sum_{j = 1}^{k}-\frac{a_i^j}{j}x^j$$

因為這個題對$x^{k + 1}$次取模了,所以後面的項可以不用再寫了。

變形一下

$$G(x) = \sum_{j = 1}^{k}(-\frac{1}{j}\sum_{i = 1}^{n}a_i^j)x^j$$

發現$1$到$k$的$sum_{i = 1}^{n}a_i^k$直接算出來了,而$i = 0$時候這東西顯然為$n$。

鼓掌~~~

現在回過頭來考慮一下這個魔術是怎麽變出來的。

考慮構造每一個$a_i$的生成函數

$$1 + a_ix + a_i^2x^2 + a_i^3x^3 + \cdots$$

把每一個$a_i$的生成函數都構造出來然後加起來的第$i$項系數就是$k = i$時候的答案了。

$$F(x) = \sum_{i = 1}^{n}\frac{1}{1 - a_ix}$$

發現這個$F(x)$並不是很好算,而

$$ln‘(1 - a_ix) = \frac{1}{1 - a_ix}$$

$$(ln(1 - a_ix))‘ = \frac{-a_i}{1 - a_ix}$$

所以先計算

$$G(x) = \sum_{i = 1}^{n}\frac{-a_i}{1 - a_ix} = (ln\prod_{i = 1}^{n}(1 - a_ix))‘$$

把這兩個式子寫回到生成函數的形式,發現

$$F(x) = -x * G(x) + n$$

於是大功告成。

用$vector$寫多項式真爽。

技術分享圖片
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
typedef vector <ll> poly;

const int N = 1e5 + 5;
const int Maxn = 1e5;

int n, m, K;
ll a[N], b[N], fac[N], ifac[N], inv[N];

template <typename T>
inline void read(T &X) {
    X = 0; char ch = 0; T op = 1;
    for (; ch > 9 || ch < 0; ch = getchar())
        if (ch == -) op = -1;
    for (; ch >= 0 && ch <= 9; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op;
}

inline void deb(poly c) {
    for (int i = 0; i < (int)c.size(); i++)
        printf("%lld%c", c[i], " \n"[i == (int)c.size() - 1]);
}

namespace Poly {
    const int L = 1 << 20;
    const ll P = 998244353LL;

    int lim, pos[L];

    inline ll fpow(ll x, ll y) {
        ll res = 1;
        for (; y > 0; y >>= 1) {
            if (y & 1) res = res * x % P;
            x = x * x % P;
        }
        return res;
    }

    template <typename T>
    inline void inc(T &x, T y) {
        x += y;
        if (x >= P) x -= P;
    }

    template <typename T>
    inline void sub(T &x, T y) {
        x -= y;
        if (x < 0) x += P;
    }

    inline void prework(int len) {
        int l = 0;
        for (lim = 1; lim < len; lim <<= 1, ++l);
        for (int i = 0; i < lim; i++)
            pos[i] = (pos[i >> 1] >> 1) | ((i & 1) << (l - 1));
    }

    inline void ntt(poly &c, int opt) {
        c.resize(lim, 0);
        for (int i = 0; i < lim; i++)
            if (i < pos[i]) swap(c[i], c[pos[i]]);
        for (int i = 1; i < lim; i <<= 1) {
            ll wn = fpow(3, (P - 1) / (i << 1));
            if (opt == -1) wn = fpow(wn, P - 2);
            for (int len = i << 1, j = 0; j < lim; j += len) {
                ll w = 1;
                for (int k = 0; k < i; k++, w = w * wn % P) {
                    ll x = c[j + k], y = w * c[j + k + i] % P;
                    c[j + k] = (x + y) % P, c[j + k + i] = (x - y + P) % P;
                }
            }
        }

        if (opt == -1) {
            ll inv = fpow(lim, P - 2);
            for (int i = 0; i < lim; i++) c[i] = c[i] * inv % P;
        }
    }

    inline poly operator * (const poly &x, const poly &y) {
        poly res, u = x, v = y;
        prework(u.size() + v.size() - 1);
        ntt(u, 1), ntt(v, 1);
        for (int i = 0; i < lim; i++) res.push_back(v[i] * u[i] % P);
        ntt(res, -1);
        res.resize(u.size() + v.size() - 1);
        return res;
    }

    poly getInv(poly x, int len) {
        x.resize(len);
        if (len == 1) {
            poly res;
            res.push_back(x[0]);
            return res;
        }
        poly y = getInv(x, (len + 1) >> 1);
        prework(len << 1);

        poly u = x, v = y, res;
        ntt(u, 1), ntt(v, 1);
        for (int i = 0; i < lim; i++) res.push_back(v[i] * (2LL - u[i] * v[i] % P + P) % P);
        ntt(res, -1);

        res.resize(len);
        return res;
    }

    inline void direv(poly &c) {
        for (int i = 0; i < (int)c.size() - 1; i++)
            c[i] = c[i + 1] * (i + 1) % P;
        c[c.size() - 1] = 0;
    }

    inline void integ(poly &c) {
        for (int i = (int)c.size() - 1; i > 0; i--)
            c[i] = c[i - 1] * inv[i] % P;
        c[0] = 0;
    }

    inline poly getLn(poly c) {
        poly a = getInv(c, (int)c.size());
        poly b = c;
        direv(b);

        poly res = b * a;
        res.resize(c.size());
        integ(res);
        return res;
    }

    inline poly solve(int l, int r, ll *c) {
        if (l == r) {
            poly res;
            res.push_back(1), res.push_back((P - c[l]) % P);
            return res;
        }

        int mid = ((l + r) >> 1);
        poly u = solve(l, mid, c), v = solve(mid + 1, r, c);
        poly res = u * v;
        res.resize(u.size() + v.size() - 1);
        return res;
    }

    inline poly mul(const poly &x, const poly &y) {
        return x * y;
    }

}

using Poly::P;
using Poly::fpow;
using Poly::inc;
using Poly::sub;
using Poly::solve;
using Poly::getLn;

inline void prework() {
    fac[0] = inv[0] = inv[1] = 1;
    for (int i = 1; i <= Maxn; i++) {
        fac[i] = fac[i - 1] * i % P;
        if (i > 1) inv[i] = (P - P / i) * inv[P % i] % P;
    }
    ifac[Maxn] = fpow(fac[Maxn], P - 2);
    for (int i = Maxn - 1; i >= 0; i--) ifac[i] = ifac[i + 1] * (i + 1) % P;
}

int main() {
/*    #ifndef ONLINE_JUDGE
        freopen("Sample.txt", "r", stdin);
    #endif    */
    
    freopen("input.txt", "r", stdin);
    freopen("my.out", "w", stdout);

    prework();

    read(n), read(m);
    for (int i = 1; i <= n; i++) read(a[i]);
    for (int i = 1; i <= m; i++) read(b[i]);
    read(K);
    ++K;

    poly Fa = solve(1, n, a), Fb = solve(1, m, b);

//    deb(Fa), deb(Fb);

    Fa.resize(K, 0), Fb.resize(K, 0);
    poly Ga = getLn(Fa), Gb = getLn(Fb);

    Ga.resize(K, 0), Gb.resize(K, 0);

//    deb(Ga), deb(Gb);

    poly A, B, C;

    A.push_back(n), B.push_back(m);
    for (int i = 1; i < K; i++) {
        A.push_back((P - Ga[i]) % P * i % P * ifac[i] % P);
        B.push_back((P - Gb[i]) % P * i % P * ifac[i] % P);
    }

//    deb(A), deb(B);

    C = Poly::mul(A, B);
    C.resize(K);

//    deb(C);

//    printf("\n");
    ll invn = fpow(n, P - 2), invm = fpow(m, P - 2);
    for (int i = 1; i < K; i++)
        printf("%lld\n", invn * invm % P * fac[i] % P * C[i] % P);

    return 0;
}
View Code

Luogu 4705 玩遊戲