洛谷 P4091 [HEOI2016/TJOI2016]求和

在2016年,佳媛姐姐刚刚学习了第二类斯特林数,非常开心。

现在他想计算这样一个函数的值:

\[f(n)=\sum_{i=0}^n\sum_{j=0}^i S(i,j)\times 2^j \times (j!) \]

S(i, j)表示第二类斯特林数,递推公式为:

\(S(i, j) = j \times S(i - 1, j) + S(i - 1, j - 1), 1 \le j \le i - 1\)

边界条件为:\(S(i, i) = 1(0 \le i), S(i, 0) = 0(1 \le i)\)

你能帮帮他吗?

不会线性做法,只会无脑化式子/kk

\[\begin{aligned} f(n)&=\sum_{i=0}^n\sum_{j=0}^i\begin{Bmatrix}i\\j\end{Bmatrix}2^jj!\\ &=\sum_{i=0}^n\sum_{j=0}^n\begin{Bmatrix}i\\j\end{Bmatrix}2^jj!\\ &=\sum_{j=0}^n2^jj!\sum_{j=0}^n\begin{Bmatrix}i\\j\end{Bmatrix} \end{aligned}\]

考虑第二类斯特林数的容斥式\(\begin{Bmatrix}n\\m\end{Bmatrix}=\frac{1}{m!}\sum_{k=0}^m(-1)^k\begin{pmatrix}m\\k\end{pmatrix}(m-k)^n\),则有

\[\begin{aligned} &=\sum_{j=0}^n2^jj!\sum_{i=0}^n\frac{1}{j!}\sum_{k=0}^i(-1)^k\begin{pmatrix}j\\k\end{pmatrix}(j-k)^i \\ &=\sum_{j=0}^n2^j\sum_{i=0}^n\sum_{k=0}^i(-1)^k\begin{pmatrix}j\\k\end{pmatrix}(j-k)^i\\ &=\sum_{j=0}^n2^j\sum_{i=0}^n\sum_{k=0}^i(-1)^k\frac{j!}{k!(j-k)!}(j-k)^i\\ &=\sum_{j=0}^n2^jj!\sum_{i=0}^n\sum_{k=0}^i\frac{(-1)^k}{k!}\times\frac{(j-k)^i}{(j-k)!}\\ &=\sum_{j=0}^n2^jj!\sum_{k=0}^j\frac{(-1)^k}{k!}\times\frac{\sum_{i=0}^n(j-k)^i}{(j-k)!} \end{aligned}\]

\(A(i)=\frac{(-1)^i}{i!},B(i)=\frac{\sum_{j=0}^ni^j}{i!}=\frac{i^{n+1}-1}{i!(i-1)}\)

那么就有

\[=\sum_{j=0}^n2^jj!\sum_{k=0}^jA(k)\times B(j-k) \]

直接ntt就可以了

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
const int N = 4e5;
const int p = 998244353;
using namespace std;
int n,a[N + 5],b[N + 5],rev[N + 5],maxn,lg,G[N + 5][2],fac[N + 5],ans;
int mypow(int a,int x){int s = 1;for (;x;x & 1 ? s = 1ll * s * a % p : 0,a = 1ll * a * a % p,x >>= 1);return s;}
void ntt(int *a,int typ)
{
    for (int i = 0;i < maxn;i++)
        if (i < rev[i])
            swap(a[i],a[rev[i]]);
    for (int i = 1;i < maxn;i <<= 1)
        for (int j = 0;j < maxn;j += i << 1)
            for (int k = 0;k < i;k++)
            {
                int x = a[j + k],t = 1ll * G[i + k][typ] * a[j + k + i] % p;
                a[j + k] = (x + t) % p;
                a[j + k + i] = (x - t) % p;
            }
    if (!typ)
    {
        int inv = mypow(maxn,p - 2);
        for (int i = 0;i < maxn;i++)
            a[i] = 1ll * a[i] * inv % p;
    }
}
int main()
{
    scanf("%d",&n);
    maxn = 1;
    while (maxn <= n * 2 + 2)
        maxn <<= 1,lg++;
    for (int i = 0;i < maxn;i++)
        rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << lg - 1);
    for (int i = 1;i < maxn;i <<= 1)
    {
        int g1 = mypow(3,(p - 1) / (i << 1)),g2 = mypow(mypow(3,p - 2),(p - 1) / (i << 1));
        G[i][0] = G[i][1] = 1;
        for (int j = 1;j < i;j++)
            G[i + j][1] = 1ll * G[i + j - 1][1] * g1 % p,G[i + j][0] = 1ll * G[i + j - 1][0] * g2 % p;
    }
    a[0] = b[0] = fac[0] = 1;
    for (int i = 1;i <= n;i++)
        fac[i] = 1ll * fac[i - 1] * i % p;
    for (int i = 1;i <= n;i++)
        a[i] = mypow(-1,i) * mypow(fac[i],p - 2),b[i] = 1ll * (mypow(i,n + 1) - 1) * mypow(1ll * fac[i] * (i - 1) % p,p - 2) % p;
    b[1] = n + 1;
    ntt(a,1);
    ntt(b,1);
    for (int i = 0;i < maxn;i++)
        a[i] = 1ll * a[i] * b[i] % p;
    ntt(a,0);
    for (int i = 0;i <= n;i++)
        ans += 1ll * mypow(2,i) * fac[i] % p * a[i] % p,ans %= p;
    cout<<(ans + p) % p<<endl;
    return 0;
}
posted @ 2020-09-05 10:42  eee_hoho  阅读(204)  评论(0编辑  收藏  举报