luogu P4091 [HEOI2016/TJOI2016]求和

https://www.luogu.com.cn/problem/P4091
大力推式子
首先要知道
S ( n , m ) = 1 m ! ∑ i = 0 m ( − 1 ) m − i C m i i n S(n,m)=\frac{1}{m!}\sum\limits_{i=0}^m(-1)^{m-i}C_m^ii^n S(n,m)=m!1i=0m(1)miCmiin
具体证明的话可以把 m n = ∑ i = 0 m S ( n , i ) × i ! × C m i m^n=\sum\limits_{i=0}^mS(n,i)\times i!\times C_m^i mn=i=0mS(n,i)×i!×Cmi二项式反演一下得到

然后开始推式子
f ( n ) = ∑ j = 0 n 2 j × j ! ∑ i = 0 n S ( i , j ) f(n)=\sum\limits_{j=0}^n 2^j\times j!\sum\limits_{i=0}^n S(i,j) f(n)=j=0n2j×j!i=0nS(i,j)
套上面那条狮子
= ∑ j = 0 n 2 j × ∑ i = 0 n ∑ k = 0 j ( − 1 ) j − k C j k k i =\sum\limits_{j=0}^n 2^j\times \sum\limits_{i=0}^n\sum\limits_{k=0}^j(-1)^{j-k}C_j^k k^i =j=0n2j×i=0nk=0j(1)jkCjkki
然后发现 i i i可以拉到后面去
= ∑ j = 0 n 2 j × ∑ k = 0 j ( − 1 ) j − k C j k ∑ i = 0 n k i =\sum\limits_{j=0}^n 2^j\times \sum\limits_{k=0}^j(-1)^{j-k}C_j^k \sum\limits_{i=0}^n k^i =j=0n2j×k=0j(1)jkCjki=0nki
可以把最后那坨设为 c a l c ( k ) = ∑ i = 0 n k i calc(k)=\sum\limits_{i=0}^n k^i calc(k)=i=0nki
= ∑ j = 0 n 2 j × ∑ k = 0 j ( − 1 ) j − k j ! k ! ( j − k ) ! c a l c ( k ) =\sum\limits_{j=0}^n 2^j\times \sum\limits_{k=0}^j(-1)^{j-k}\frac{j!}{k!(j-k)!}calc(k) =j=0n2j×k=0j(1)jkk!(jk)!j!calc(k)

j ! j! j!提到前面然后大力卷积即可
大力NTT卷积即可
code:

#include<bits/stdc++.h>
#define N 400050
#define mod 998244353
using namespace std;
int add(int x, int y) { x += y;
    if(x >= mod) x -= mod;
    return x;
}
int sub(int x, int y) { x -= y;
    if(x < 0) x += mod;
    return x;
}
int mul(int x, int y) {
    return 1ll * x * y % mod;
}
int qpow(int x, int y) {
    int ret = 1;
    for(; y; y >>= 1, x = mul(x, x)) if(y & 1) ret = mul(ret, x);
    return ret;
}
const int G = 3;
const int G_inv = qpow(G, mod - 2);
int rev[N];
void ntt(int *a, int n, int o) {
    for(int i = 1; i < n; i ++)
        if(rev[i] > i) swap(a[i], a[rev[i]]);
    for(int len = 2; len <= n; len <<= 1) {
        int w0 = qpow(o == 1? G : G_inv, (mod - 1) / len);
        for(int j = 0; j < n; j += len) {
            int wn = 1;
            for(int k = j; k < j + (len >> 1); k ++, wn = mul(wn, w0)) {
                int X = a[k], Y = mul(wn, a[k + (len >> 1)]);
                a[k] = add(X, Y), a[k + (len >> 1)] = sub(X, Y);
            }
        }
    }
    int ninv = qpow(n, mod - 2);
    if(o == -1)
        for(int i = 0; i < n; i ++) a[i] = mul(a[i], ninv);
}
int fac[N], ifac[N], mi[N];
void init(int n) {
    fac[0] = mi[0] = 1;
    for(int i = 1; i <= n; i ++) fac[i] = mul(fac[i - 1], i), mi[i] = mul(mi[i - 1], 2);
    ifac[n] = qpow(fac[n], mod - 2);
    for(int i = n - 1; i >= 0; i --) ifac[i] = mul(ifac[i + 1], i + 1);
}
int n, f[N], g[N];
int main() {
    scanf("%d", &n);
    init(n);
    for(int i = 0; i <= n; i ++) f[i] = mul(qpow(mod - 1, i), ifac[i]);
    g[0] = 1, g[1] = n + 1;
    for(int i = 2; i <= n; i ++) g[i] = mul(sub(qpow(i, n + 1), 1), mul(qpow(i - 1, mod - 2), ifac[i]));
    int len = 1;
    for(; len <= n + n; len <<= 1);
    for(int i = 1; i < len; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i&1) * (len >> 1));
    
    ntt(f, len, 1), ntt(g, len, 1);
    for(int i = 0; i < len; i ++) f[i] = mul(f[i], g[i]);
    ntt(f, len, -1);
    int ans = 0;
    for(int i = 0; i <= n; i ++) ans = add(ans, mul(mi[i], mul(fac[i], f[i])));
    printf("%d", ans);
    return 0;
}

posted @ 2021-07-17 16:35  lahlah  阅读(50)  评论(0编辑  收藏  举报