【LG4091】[HEOI2016/TJOI2016]求和

【LG4091】[HEOI2016/TJOI2016]求和

标签(空格分隔): 数论、数学---FFT&NTT 数论、数学---组合数学 Source---各省省选


题面

要你求:

\[ \sum_{i=0}^n\sum_{j=0}^iS(i,j)*2^j*j! \]

其中\(S\)表示第二类斯特林数,\(n\leq10^5\),答案对\(998244353\)取模。

题解

这题你们好早就做了,因为由于技术原因(不会\(NTT\)),我现在才做,我真是菜爆了。

先来推柿子:

\(\because S(i,j)=0(i < j)\)

\(\therefore\;\)原式\(=\sum_{i=0}^n\sum_{j=0}^nS_i^j*2^j*j!\)

\(2^j*j!\)提到前面:

\[ \sum_{j=0}^n2^j*(j!)\sum_{i=0}^nS_i^j \]

\(\because\;S_n^m=\frac {1}{m!}(-1)^iC_m^i(m-i)^n\)

\(\therefore S_n^m=\sum_{i=0}^m\frac {(-1)^i}{i!}\frac {(m-i)^n}{(m-i)!}\)

那么原式\(=\)

\[ \sum_{j=0}^n2^j*j!\sum_{i=0}^n\sum_{k=0}^j\frac {(-1)^k}{k!}\frac {(j-k)^i}{(j-k)!}\\ \Leftrightarrow \sum_{j=0}^n2^j*j!\sum_{k=0}^j\frac {(-1)^k}{k!}\frac {\sum_{i=0}^n(j-k)^i}{(j-k)!}\\ \]

然后发现其实后面那一坨是

\[ f(i)=\frac {(-1)^i}{i!}\\ g(i)=\frac {\sum_{j=0}^ni^j}{i!}=\frac {i^{n+1}-1}{(i-1)i!} \]

的卷积,直接\(NTT\)搞就好了。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring> 
#include <cmath> 
#include <algorithm>
using namespace std; 
const int Mod = 998244353; 
int fpow(int x, int y) { 
    int res = 1; 
    while (y) {
        if (y & 1) res = 1ll * res * x % Mod; 
        x = 1ll * x * x % Mod; 
        y >>= 1; 
    }
    return res; 
} 
const int G = 3, iG = fpow(G, Mod - 2);
const int MAX_N = 3e5 + 5; 
int Limit, rev[MAX_N]; 
void NTT(int *p, int op) { 
    for (int i = 0; i < Limit; i++) if (i < rev[i]) swap(p[i], p[rev[i]]); 
    for (int i = 1; i < Limit; i <<= 1) {
        int rot = fpow(op == 1 ? G : iG, (Mod - 1) / (i << 1)); 
        for (int j = 0; j < Limit; j += (i << 1)) { 
            int w = 1; 
            for (int k = 0; k < i; k++, w = 1ll * w * rot % Mod) { 
                int x = p[j + k], y = 1ll * w * p[i + k + j] % Mod; 
                p[j + k] = (x + y) % Mod, p[i + j + k] = (x - y + Mod) % Mod; 
            } 
        } 
    }
    if (op == -1) {
        int inv = fpow(Limit, Mod - 2); 
        for (int i = 0; i < Limit; i++) p[i] = 1ll * p[i] * inv % Mod;
    } 
} 
int N, f[MAX_N], g[MAX_N]; 
int main () {
#ifndef ONLINE_JUDGE 
    freopen("cpp.in", "r", stdin); 
#endif 
    cin >> N; f[0] = 1, g[0] = 1; 
    for (int i = 1, fac = 1; i <= N; fac = 1ll * fac * (++i) % Mod) { 
        f[i] = (1ll * ((i & 1) ? -1 : 1) * fpow(fac, Mod - 2) % Mod + Mod) % Mod; 
        g[i] = 1ll * (fpow(i, N + 1) + Mod - 1) % Mod * fpow(1ll * (i - 1) * fac % Mod, Mod - 2) % Mod; 
    }
    g[1] = N + 1; 
    int p = 0; 
    for (Limit = 1; Limit <= (N << 1); Limit <<= 1, ++p) ;
    for (int i = 0; i < Limit; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (p - 1)); 
    NTT(f, 1), NTT(g, 1); 
    for (int i = 0; i < Limit; i++) f[i] = 1ll * f[i] * g[i] % Mod;
    NTT(f, -1); 
    int ans = 0, fac = 1, pw = 1; 
    for (int i = 0; i <= N; i++, fac = 1ll * fac * i % Mod, pw = 2ll * pw % Mod)
        ans = (ans + 1ll * fac * pw % Mod * f[i] % Mod) % Mod; 
    printf("%d\n", ans); 
    return 0; 
} 

猜你喜欢

转载自www.cnblogs.com/heyujun/p/10344376.html