BZOJ4555 [Tjoi2016&Heoi2016]求和 【第二类斯特林数 + NTT】

题目

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

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

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

S(i, j) = j ? S(i ? 1, j) + S(i ? 1, j ? 1), 1 <= j <= i ? 1。

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

你能帮帮他吗?

输入格式

输入只有一个正整数

输出格式

输出f(n)。由于结果会很大,输出f(n)对998244353(7 × 17 × 223 + 1)取模的结果即可。1 ≤ n ≤ 100000

输入样例

3

输出样例

87

题解

当第二类斯特林数\(j > i\)时值为\(0\)

所以我们实际求:

\[
\begin{aligned}
ans &= \sum\limits_{i = 0}^{n} \sum\limits_{j = 0}^{n} \begin{Bmatrix} i \\ j \end{Bmatrix} 2^{j}j! \&= \sum\limits_{i = 0}^{n} \sum\limits_{j = 0}^{n} 2^{j}j! \frac{1}{j!} \sum\limits_{k = 0}^{j} (-1)^{k}{j \choose k}(j - k)^{i} \&= \sum\limits_{i = 0}^{n} \sum\limits_{j = 0}^{n} 2^{j}j! \sum\limits_{k = 0}^{j} \frac{(-1)^{k}}{k!} * \frac{(j - k)^{i}}{(j - k)!} \&= \sum\limits_{j = 0}^{n} 2^{j}j! \sum\limits_{k = 0}^{j} \frac{(-1)^{k}}{k!} * \frac{\sum\limits_{i = 0}^{n} (j - k)^{i}}{(j - k)!} \\end{aligned}
\]

NTT即可

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<‘ ‘; puts("");
using namespace std;
const int maxn = 400005,maxm = 100005,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57){if (c == ‘-‘) flag = -1; c = getchar();}
    while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    return out * flag;
}
const int G = 3,P = 998244353;
int fac[maxn],fv[maxn],inv[maxn],bin[maxn],g[maxn];
int L,R[maxn],A[maxn],B[maxn],n,m,N;
inline int qpow(int a,int b){
    int ans = 1;
    for (; b; b >>= 1,a = 1ll * a * a % P)
        if (b & 1) ans = 1ll * ans * a % P;
    return ans;
}
void init(){
    fac[0] = fac[1] = inv[0] = inv[1] = fv[0] = fv[1] = 1;
    bin[0] = 1; bin[1] = 2;
    g[0] = 1; g[1] = N + 1;
    for (int i = 2; i <= N; i++){
        fac[i] = 1ll * fac[i - 1] * i % P;
        inv[i] = 1ll * (P - P / i) * inv[P % i] % P;
        fv[i] = 1ll * fv[i - 1] * inv[i] % P;
        bin[i] = 2ll * bin[i - 1] % P;
        g[i] = 1ll * (1ll * qpow(i,N + 1) - 1 + P) % P * inv[i - 1] % P;
    }
}
void NTT(int* a,int f){
    for (int i = 0; i < n; i++) if (i < R[i]) swap(a[i],a[R[i]]);
    for (int i = 1; i < n; i <<= 1){
        int gn = qpow(G,(P - 1) / (i << 1));
        for (int j = 0; j < n; j += (i << 1)){
            int g = 1,x,y;
            for (int k = 0; k < i; k++,g = 1ll * g * gn % P){
                x = a[j + k]; y = 1ll * g * a[j + k + i] % P;
                a[j + k] = (x + y) % P; a[j + k + i] = ((x - y) % P + P) % P;
            }
        }
    }
    if (f == 1) return;
    int nv = qpow(n,P - 2); reverse(a + 1,a + n);
    for (int i = 0; i < n; i++) a[i] = 1ll * a[i] * nv % P;
}
int main(){
    N = read();
    init();
    for (int i = 0; i <= N; i++){
        A[i] = ((i & 1) ? -1ll : 1ll) * fv[i] % P;
        B[i] = 1ll * g[i] * fv[i] % P;
    }
    m = N + N; L = 0;
    for (n = 1; n <= m; n <<= 1) L++;
    for (int i = 1; i < n; i++) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
    NTT(A,1); NTT(B,1);
    for (int i = 0; i < n; i++) A[i] = 1ll * A[i] % P * B[i] % P;
    NTT(A,-1);
    int ans = 0;
    for (int i = 0; i <= N; i++)
        ans = (ans + 1ll * bin[i] * fac[i] % P * A[i] % P) % P;
    printf("%d\n",(ans % P + P) % P);
    return 0;
}

原文地址:https://www.cnblogs.com/Mychael/p/8975630.html

时间: 2024-10-07 18:33:05

BZOJ4555 [Tjoi2016&Heoi2016]求和 【第二类斯特林数 + NTT】的相关文章

bzoj 5093 图的价值 —— 第二类斯特林数+NTT

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5093 每个点都是等价的,从点的贡献来看,得到式子: \( ans = n * \sum\limits_{d=0}^{n-1} d^{k} * 2^{C_{n-1}^{2}} * C_{n-1}^{d} \) 使用 \( n^{k} = \sum\limits_{i=0}^{k} S(k,i) * i! *C_{n}^{i} \) 得到 \( ans = n * \sum\limits_{d

bzoj5093:图的价值(第二类斯特林数+NTT)

传送门 首先,题目所求为\[n\times 2^{C_{n-1}^2}\sum_{i=0}^{n-1}C_{n-1}^ii^k\] 即对于每个点\(i\),枚举它的度数,然后计算方案.因为有\(n\)个点,且关于某个点连边的时候剩下的边都可以随便连,所以有前面的两个常数 所以真正要计算的是\[\sum_{i=0}^{n-1}C_{n-1}^ii^k\] 根据第二类斯特林数的性质,有\[i^k=\sum_{j=0}^iS(k,j)\times j!\times C_i^j\] 然后带入,得\[\s

[HEOI2016/TJOI2016]求和——第二类斯特林数

给你斯特林数就换成通项公式,给你k次方就换成斯特林数 考虑换成通项公式之后,组合数没有什么好的处理方法 直接拆开,消一消阶乘 然后就发现了(j-k)和k! 往NTT方向靠拢 然后大功告成 其实只要想到把斯特林公式换成通项公式,考虑用NTT优化掉(j-k)^i 后面都是套路了. #include<bits/stdc++.h> #define reg register int #define il inline #define numb (ch^'0') #define int long long

bzoj 4555 [Tjoi2016&amp;Heoi2016]求和 NTT 第二类斯特林数 等比数列求和优化

[Tjoi2016&Heoi2016]求和 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 679  Solved: 534[Submit][Status][Discuss] Description 在2016年,佳媛姐姐刚刚学习了第二类斯特林数,非常开心. 现在他想计算这样一个函数的值: S(i, j)表示第二类斯特林数,递推公式为: S(i, j) = j ∗ S(i − 1, j) + S(i − 1, j − 1), 1 <= j &l

【BZOJ 4555】[Tjoi2016&amp;Heoi2016]求和 NTT+第二类斯特林数

用到第二类斯特林数的性质,做法好像很多,我打的是直接ntt,由第二类斯特林数的容斥公式可以推出,我们可以对于每一个i,来一次ntt求出他与所有j组成的第二类斯特林数的值,这个时候我们是O(n^2logn)的,还不如暴力,但是我们发现,对于刚刚提到的容斥的式子,将其化为卷积形式后,其一边的每一项对于每一个i都相同,另一边的每一项是对于所有的i形成一个n项的等比数列,这样我们可以把成等比数列的一边求和,用固定的一边去卷他们的和,这时候的答案的每一项就是所有的i的这一项的和,然后我们再O(n)乘上阶乘

【BZOJ4555】求和(第二类斯特林数,组合数学,NTT)

[BZOJ4555]求和(第二类斯特林数,组合数学,NTT) 题面 BZOJ 题解 推推柿子 \[\sum_{i=0}^n\sum_{j=0}^iS(i,j)·j!·2^j\] \[=\sum_{i=0}^n\sum_{j=0}^nS(i,j)·j!·2^j\] \[=\sum_{i=0}^n\sum_{j=0}^nj!·2^j(\frac{1}{j!}\sum_{k=0}^j(-1)^k·C_j^k·(j-k)^i)\] \[=\sum_{j=0}^n2^j\sum_{k=0}^j(-1)^k

HDU 4045 Machine scheduling (第二类斯特林数+DP)

A Baidu's engineer needs to analyze and process large amount of data on machines every day. The machines are labeled from 1 to n. On each day, the engineer chooses r machines to process data. He allocates the r machines to no more than m groups ,and

奇怪的数学题(51nod1847)——min_25筛+杜教筛+第二类斯特林数

题面 51nod1847 解析   定义$f(i)$为$i$的次大因数,特别地$f(1)=0$  那么我们就是去求$$\sum_{i=1}^{n}\sum_{j=1}^{n}f^{m}(gcd(i, j))$$ 这种东西的套路就是枚举$gcd$然后用欧拉函数处理, \begin{align*}\sum_{i=1}^{n}\sum_{j=1}^{n}f^{m}(gcd(i, j)) &= \sum_{i=1}^{n}\sum_{j=1}^{\left \lfloor \frac{n}{i}\rig

Gym 101147G 第二类斯特林数

大致题意: n个孩子,k场比赛,每个孩子至少参加一场比赛,且每场比赛只能由一个孩子参加.问有多少种分配方式. 分析: k>n,就无法分配了. k<=n.把n分成k堆的方案数乘以n的阶乘.N分成k堆得方案数即第二类斯特林数 http://blog.csdn.net/acdreamers/article/details/8521134 #include <bits/stdc++.h> using namespace std; typedef long long ll; const ll