zoukankan      html  css  js  c++  java
  • Luogu 4091 [HEOI2016/TJOI2016]求和

    BZOJ 4555

    一道模板题。

    第二类斯特林数有公式:

    $$S(n, m) = frac{1}{m!}sum_{i = 0}^{m}(-1)^iinom{m}{i}(m - i)^n$$

    考虑它的组合意义:$S(n, m)$表示$n$个不相同的小球放到$m$个相同的盒子里而且不能有空盒的方案数。

    我们枚举空盒有$i$个,然后进行容斥。因为盒子没有区别,所以最后得到的值还要除以$m!$。

    本题要求:

    $$sum_{i = 0}^{n}sum_{j = 0}^{i}S(i, j)*2^j*(j!)$$

    $$=sum_{j = 0}^{n}2^j*(j!)sum_{i = 0}^{n}S(i, j)$$

    $$=sum_{j = 0}^{n}2^j*(j!)sum_{i = 0}^{n}frac{1}{j!}sum_{k = 0}^{j}(-1)^kinom{j}{k}(j - k) ^ i$$

    $$=sum_{j = 0}^{n}2^jsum_{i = 0}^{n}sum_{k = 0}^{j}(-1)^kfrac{j!}{k!(j - k)!}*(j - k)^i$$

    $$=sum_{j = 0}^{n}2^j*(j!)sum_{k = 0}^{j}frac{(-1^k)}{k!} * frac{sum_{i = 0}^{n}(j - k)^i}{(j - k)!}$$

    记$f(i) = frac{(-1^k)}{k!}$,$g(i) = frac{sum_{j = 0}^{n}i^j}{(i)!}$,

    因为$S(0, 0) = (-1)^0 * 1 * 0^0 = 1$,所以记$g(0) = 1$,$g(1) = n + 1$,剩下代入等比数列求和公式。

    那么原式化为

    $$sum_{i = 0}^{n}2^i*(i!)(f*g)(i)$$

    做一遍$NTT$就好了。

    时间复杂度$O(nlogn)$。

    Code:

    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    
    const int N = 3e5 + 5;
    const ll P = 998244353LL;
    
    int n, lim = 1, pos[N];
    ll f[N], g[N], fac[N], inv[N], bin[N];
    
    template <typename T>
    inline void swap(T &x, T &y) {
        T t = x; x = y; y = t;
    }
    
    template <typename T>
    inline void inc(T &x, T y) {
        x += y;
        if(x >= P) x -= P;
    }
    
    inline ll fpow(ll x, ll y) {
        ll res = 1LL;
        for (; y > 0; y >>= 1) {
            if (y & 1) res = res * x % P;
            x = x * x % P;
        }
        return res;
    }
    
    inline void prework() {
        int l = 0;
        for (; lim <= n * 2; ++l, lim <<= 1);
        for (int i = 0; i < lim; i++)
            pos[i] = (pos[i >> 1] >> 1) | ((i & 1) << (l - 1)); 
    }
    
    inline void ntt(ll *c, int opt) {
        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 = 1LL;
                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 invP = fpow(lim, P - 2);
            for (int i = 0; i < lim; i++)
                c[i] = c[i] * invP % P;
        }
    }
    
    int main() {
        scanf("%d", &n);
        
        bin[0] = fac[0] = 1LL;
        for (int i = 1; i <= n; i++) {
            fac[i] = fac[i - 1] * i % P;
            bin[i] = bin[i - 1] * 2LL % P;
        }
        inv[n] = fpow(fac[n], P - 2);
        for (int i = n - 1; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1) % P;
        
    /*    for (int i = 0; i <= n; i++)
            printf("%lld%c", inv[i] * fac[i] % P, i == n ? '
    ' : ' ');   */
        
        for (int i = 0; i <= n; i++) {
            f[i] = ((i & 1) ? (-1LL) : (1LL)) * inv[i] % P;
            if(f[i] < 0) f[i] += P;
            if(i == 0) g[i] = 1LL;
            else if (i == 1) g[i] = n + 1;
            else g[i] = (fpow(i, n + 1) - 1 + P) % P * fpow(i - 1, P - 2) % P;
            g[i] = g[i] * inv[i] % P;
        }
        
        prework();
        ntt(f, 1), ntt(g, 1);
        for (int i = 0; i < lim; i++) f[i] = f[i] * g[i] % P;
        ntt(f, -1);
        
        ll ans = 0LL;
        for (int i = 0; i <= n; i++) 
            inc(ans, bin[i] * fac[i] % P * f[i] % P);
        
        printf("%lld
    ", ans);
        return 0;
    }
    View Code
  • 相关阅读:
    VIJOS-P1446 最短路上的统计
    洛谷 CF997A Convert to Ones
    USACO Your Ride Is Here
    NOIP 2006 明明的随机数
    NOIP 2008 传球游戏
    数据结构—链表详解
    洛谷 P1160 队列安排
    洛谷 P1167 刷题
    JDOJ 2982: 最大连续子段和问题
    洛谷 P1123 取数游戏
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/10183716.html
Copyright © 2011-2022 走看看