luogu P4091 [HEOI2016/TJOI2016]求和 FFT

又是一道神仙题orz

我们先化一化式子。

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

看着\(\displaystyle \sum_{j=0}^i\)很不爽,因为当\(j>i\)时,\(S(i,j)=0\),所以

\(\displaystyle Ans[n]=\sum_{i=0}^n\sum_{j=0}^nS(i,j)\times 2^j\times (j!)\)

看着\(S(i,j)\)很不爽,我们先把它单独拎出来。

$\displaystyle Ans[n]=\sum_{j=0}^n2^j\times (j!)\sum_{i=0}^nS(i,j) $

注意这里枚举\(i,j\)的顺序发生了改变,但式子依然等价。

这里先放个结论:

\(\displaystyle S(i,j)=\frac{1}{j!}\sum_{k=0}^j(-1)^k C_{j}^{k} (j-k)^i\)

这个可以用容斥原理来解释,第二类斯特林数是将i个不同的球,j个相同的盒子,不能空的方案数,现将盒子看成不一样的,并且能空,枚举空盒的个数\(C_{j}^{k}\), 其余的随便放\((j-k)^i\), 乘上容斥系数\((-1)^k\),在乘上\(\displaystyle \frac{1}{j!}\)将盒子变成一样的。

带进\(\displaystyle S(i,j)=\frac{1}{j!}\sum_{k=0}^j(-1)^k C_{j}^{k} (j-k)^i\)发现:

$\displaystyle Ans[n]=\sum_{j=0}^n2^j\times (j!)\sum_{i=0}^n \frac{1}{j!}\sum_{k=0}^j(-1)^k C_{j}^{k} (j-k)^i $

$\displaystyle Ans[n]=\sum_{j=0}^n2^j \sum_{i=0}^n \sum_{k=0}^j(-1)^k C_{j}^{k} (j-k)^i $

\(\displaystyle C_j^k=\frac{j!}{k!(j-k)!}\) 带进去。

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

$\displaystyle Ans[n]=\sum_{j=0}^n 2^j (j)! \sum_{i=0}^n \sum_{k=0}^j \frac{(-1)^k}{k!} \frac{(j-k)^i}{(j-k)!} $

看着\(\displaystyle \frac{(j-k)^i}{(j-k)!}\)非常不清真,又因为只有它带着\(i\),所以我们再次改变枚举顺序。

$\displaystyle Ans[n]=\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)!} $

我们设\(\displaystyle f[k]=\frac{(-1)^k}{k!}\) \(\displaystyle g[k]=\frac{\sum_{i=0}^n k^i}{k!}\)式子就变成了

$\displaystyle Ans[n]=\sum_{j=0}^n 2^j (j)! \sum_{k=0}^j f[k]g[j-k] $

$\displaystyle Ans[n]=\sum_{j=0}^n 2^j (j)! (f*g)(j) $

\((f*g)(j)\)的含义就是\(f\)卷上\(g\)\(x^j\)的系数。

后面的\(\displaystyle g[k]=\frac{\sum_{i=0}^n k^i}{k!}\)貌似可以等比数列求和,根据等比数列求和的知识我们知道\(\displaystyle \sum_{i=0}^n k^i=\frac{k^{n+1}-1}{k-1}\)

所以\(\displaystyle g[k]=\frac{k^{n+1}-1}{(k-1)k!}\)

注意

\(g[0]=1\)\(0^0\)并没有意义,但是\(S(0,0)=1\),所以\(g[0]=1\))。

\(g[1]=n+1\),(k=1时并不能等比数列求和,但显然\(g[1]=n+1\)

NTT一波带走就行了。

#include<iostream>
#include<cstdio>
#define DB double
#define LL long long
using namespace std;
int n;
const int N = 400010, mod = 998244353, G = 3, Ginv = (mod + 1) / 3;
int r[N];
LL ans, two = 1;
LL g[N], f[N], jc[N], inv[N];
LL ksm(LL a, LL b, LL mod) 
{
    LL res = 1;
    for (; b; b >>= 1, a = a * a % mod)
        if (b & 1)res = res * a % mod;
    return res;
}
void NTT(LL *A, int lim, int opt) 
{
    for (int i = 0; i < lim; ++i)
        if (i < r[i])swap(A[i], A[r[i]]);
    int len;
    LL wn, w, x, y;
    for (int mid = 1; mid < lim; mid <<= 1) 
    {
        len = mid << 1;
        wn = ksm(opt == 1 ? G : Ginv, (mod - 1) / len, mod);
        for (int j = 0; j < lim; j += len) 
        {
            w = 1;
            for (int k = j; k < j + mid; ++k, w = w * wn % mod) 
            {
                x = A[k]; y = A[k + mid] * w % mod;
                A[k] = (x + y) % mod;
                A[k + mid] = (x - y + mod) % mod;
            }
        }
    }
    if (opt == 1)return;
    int ni = ksm(lim, mod - 2, mod);
    for (int i = 0; i < lim; ++i)A[i] = A[i] * ni % mod;
}
void MUL(LL *A, int n, LL *B, int m) 
{
    int lim = 1;
    while (lim < (n + m))lim <<= 1;
    for (int i = 0; i < lim; ++i)
        r[i] = (r[i >> 1] >> 1) | ((i & 1) ? (lim >> 1) : 0);
    NTT(A, lim, 1); NTT(B, lim, 1);
    for (int i = 0; i < lim; ++i)A[i] = A[i] * B[i] % mod;
    NTT(A, lim, -1);
}
void YYCH() 
{
    inv[0] = inv[1] = jc[0] = jc[1] = 1;
    for (int i = 2; i <= n; ++i)jc[i] = jc[i - 1] * i % mod;
    inv[n] = ksm(jc[n], mod - 2, mod);
    for (int i = n - 1; i >= 1; --i)inv[i] = inv[i + 1] * (i + 1) % mod;
    for (int i = 0; i <= n; ++i)f[i] = (i & 1) ? mod - inv[i] : inv[i];
    g[0] = 1; g[1] = n + 1;
    for (int i = 2; i <= n; ++i)
        g[i] = (ksm(i, n + 1, mod) - 1) * ksm(i - 1, mod - 2, mod) % mod * inv[i] % mod;
}
int main() 
{
    cin >> n;
    YYCH();
    MUL(f, n, g, n);
    for (int i = 0; i <= n; ++i, two = two * 2 % mod)
        (ans += two * jc[i] % mod * f[i] % mod) %= mod;
    cout << ans;
    return 0;
}
全部评论

相关推荐

10-09 00:50
已编辑
长江大学 算法工程师
不期而遇的夏天:1.同学你面试评价不错,概率很大,请耐心等待;2.你的排名比较靠前,不要担心,耐心等待;3.问题不大,正在审批,不要着急签其他公司,等等我们!4.预计9月中下旬,安心过节;5.下周会有结果,请耐心等待下;6.可能国庆节前后,一有结果我马上通知你;7.预计10月中旬,再坚持一下;8.正在走流程,就这两天了;9.同学,结果我也不知道,你如果查到了也告诉我一声;10.同学你出线不明朗,建议签其他公司保底!11.同学你找了哪些公司,我也在找工作。
点赞 评论 收藏
分享
11-03 14:38
重庆大学 Java
AAA求offer教程:我手都抬起来了又揣裤兜了
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务