自然数幂和——第一类Stirling数和第二类Stirling数

2023-11-21 11:11

本文主要是介绍自然数幂和——第一类Stirling数和第二类Stirling数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

第一类Stirling数

首先设

$$S_k(n)=\sum_{i=0}^ni^k$$

根据第一类斯特林数的定义(P是排列数,C是组合数,s是Stirling)

$$C_n^k={P_n^k\over k!}={\sum_{i=0}^k(-1)^{i+k}s(k,i)n^i\over k!}$$

变形得

$$ n^k ={\sum_{i=0}^{k-1}(-1)^{i+k}s(k,i)n^i}-k! C_n^k$$

$n$ 从1取到n累加,

$$S_k(n)=\sum_{j=0}^n(k!C_j^k-\sum_{i=0}^{k-1}(-1)^{i+k}s(k,i)j^i)$$

拆括号

$$=k!\sum_{j=0}^nC_j^k-\sum_{i=0}^{k-1}(-1)^{i+k}s(k,i)\sum_{j=0}^nj^i$$

因为 $ C_{m+1}^{n+1}=C_m^n+C_{m}^{n+1} $,可推出 $\sum_{i=0}^nC_i^k=C_{n+1}^{k+1}$,

在转换为用排列数的

$$S_n(k)={P_{n+1}^{k+1}\over k+1}-\sum_{i=0}^{k-1}(-1)^{i+k}s(k,i)S_i(n)$$

那么我们只需要用 $O(k^2)$ 地预处理出第一类斯特林数,然后按k来递推了,边界是 $S_1(n)=n(n+1)/2$

主要运用了第一类斯特林数与排列式P的关系。

优点是可以避开除法,不用考虑模数有没有逆元,排列数的形式一定可以整除($k+1$ 个连续值相乘,其中肯定有 $k+1$ 的倍数)

//单次查询是 $O(k^2)$,多组测试就gg了,不知道有什么好的实现方法

#include<bits/stdc++.h>
using namespace std;typedef long long ll;
const ll mod = 1e9 + 7;
const int maxk = 2000 + 1;
ll n, k;ll stir[maxk][maxk];
void init()
{stir[0][0] = stir[1][1] = 1;for(int i = 2;i < maxk;i++)for(int j = 1;j <= i;j++)stir[i][j] = (stir[i-1][j-1] + (i-1)*stir[i-1][j]) % mod;
}ll S[maxk];     //S[i]表示前n项的i次方之和
ll cal()
{n %= mod;S[1] = (n+1) * n / 2 % mod;  //假设 k>=1for(int i = 2;i <= k;i++){//计算前面一坨
        ll prod;if(i > n)  prod = 0;else{ll kk = i+1;prod = 1;for(ll j = 0;j <= i;j++){ll tmp = n+1-j;if(tmp % (i+1) == 0)  prod = prod * (tmp/(i+1)) % mod;else prod = prod * tmp % mod;}}ll tmp = 0, sig;for(int j = 0;j < i;j++){sig = (j+i)&1 ? -1 : 1;tmp = (tmp + sig*stir[i][j]*S[j]%mod + mod) % mod;}S[i] = ((prod - tmp)%mod + mod) % mod;}return S[k];
}int main()
{init();int T;scanf("%d", &T);while(T--){scanf("%lld%lld", &n, &k);printf("%lld\n", cal());}return 0;
}
View Code

 

第二类Stirling数

首先需要证明一个式子

$$i^k = \sum_{j=1}^kS(k, j)*C_i^j*j!$$

证:对于一个 $i^k$,可以具体理解为把 $k$ 个不同的球放入 $i$ 个不同盒子里的方案数(允许空盒);

现在,枚举恰好有 $j$ 个盒子放有球,$j$ 可从1取到 $k$,所以方案数为 $\sum_{j=1}^kS(k, j)*C_i^j*j!$;

证毕。

$\sum \limits ^{n}_{i=0} i^k = \sum \limits _{i=0}^{n}\sum\limits _{j=1}^{k} S_{k,j}*C_{i,j}*j!$

然后讨论 $S(k, j)$ 的系数和:$\sum \limits ^{n}_{i=0} C_{i,j} *j!$,即 $j!* \sum\limits^{n}_{i=0} C_{i,j}$

已知:$\sum \limits_{i=0}^{n}C_{i,j}=C_{n+1,j+1}$

所以 $S(k, j)$ 的系数为 $j!*C_{n+1}^{j+1}$,

于是 $\sum \limits ^{n}_{i=0} i^k= \sum\limits_{j=1}^{k}S(k, j)*j!*C_{n+1}^{j+1}$.

变成排列数形式:$\displaystyle \sum \limits ^{n}_{i=0} i^k= \sum\limits_{i=1}^{k}S(k, i)* \frac{P_{n+1}^{i+1}}{{i+1}}$

然后预处理斯特林数就可以解决了.  

//同样单次查询是 $O(k^2)$

#include<bits/stdc++.h>
using namespace std;typedef long long ll;
const ll mod = 1e9 + 7;
const int maxk = 2000 + 1;
ll n, k;ll stir[maxk][maxk];
void init()
{stir[0][0] = stir[1][1] = 1;for(int i = 2;i < maxk;i++)for(int j = 1;j <= i;j++)stir[i][j] = (stir[i-1][j-1] + j*stir[i-1][j]) % mod;
}ll cal()
{n %= mod;ll sum = 0;for(int i = 1;i <= k;i++){ll prod;if(i > n)  prod = 0;else{prod = 1;for(int j = 0;j <= i;j++){ll tmp = n+1-j;if(tmp % (i+1) == 0)  tmp /= (i+1);prod = prod * tmp % mod;}}//printf("%lld\n", prod);sum = (sum + stir[k][i]*prod) % mod;}return sum;
}int main()
{init();int T;scanf("%d", &T);while(T--){scanf("%lld%lld", &n, &k);printf("%lld\n", cal());}return 0;
}
View Code

 

 

参考链接:

1. https://www.cnblogs.com/Zerokei/p/9726879.html

2. https://blog.csdn.net/lyd_7_29/article/details/75041818

转载于:https://www.cnblogs.com/lfri/p/11561451.html

这篇关于自然数幂和——第一类Stirling数和第二类Stirling数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/401996

相关文章

要求输出1~n*n的自然数构成的魔方阵。(n15且为奇数)

【描述】 输出"魔方阵"。所谓魔方阵是指这样的方阵,它的每一行、每一列和对角线之和均相等。例如,三阶魔方阵为       8 1 6       3 5 7       4 9 2 要求输出1~n*n的自然数构成的魔方阵。(n<15且为奇数) 【解题思路】 (1)第一个位置在第一行正中。 (2)新位置应处于 最近一个插入位置右上方,但如果右上方位置已超出方阵上边界,则新位置应选 列的最下

探寻C/C++中更快的大数(自然数集)模板

本文系fcbruce个人原创整理,转载请注明出处http://blog.csdn.net/u012965890/article/details/40432511,谢谢! 我们知道在C/C++中int型可处理-2^31~2^31-1(32位及以上编译器),long long型可处理-2^63~2^63-1的数据,这实际上是非常有限的,在很多情况下,我们往往会处理范围更大的数据。Java中有B

组合数学 —— 斯特林数(Stirling)

【第一类斯特林数】 1.定理 第一类斯特林数 S1(n,m) 表示的是将 n 个不同元素构成 m 个圆排列的数目。 2.递推式 设人被标上1,2,.....p,则将这 p 个人排成 m 个圆有两种情况: 在一个圆圈里只有标号为 p 的人自己,排法有 S1(n-1,m-1) 个。p 至少和另一个人在一个圆圈里。 这些排法通过把 1,2....n-1 排成 m 个圆再把 n 放在 1,2.

Light OJ 1236 Race 第二类斯特林数

第二类斯特林数 n 匹马 分成1 2 3... n组 每一组就是相同排名 没有先后 然后组与组之间是有顺序的 在乘以组数的阶乘 #include <cstdio>#include <cstring>using namespace std;int dp[1010][1010];int a[1010];int main(){a[0] = 1;dp[0][0] = 1;for(int

(c语法百题10)分离自然数

 知识点: /  % 的灵活运用。 内容: 一个三位自然数,分离出它的百位、十位与个位上的数字 输入说明: 一行一个三位整数 输出说明: 一行三个数字 , 空格隔开。分别是百 十 个位数字 输入样例: 256 输出样例 : 2 5 6 #include <stdio.h>int main(){int a;scanf("%d",&a);

Hdu 3625 Examining the Rooms[第一类斯特林数]

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3625 题目意思: n(n <= 20)个房间。n把钥匙。每个房间有一把钥匙。一把钥匙只能开一把锁。 现在一个人手里没有钥匙,他可以强行打开一个门,然后拿出这个房间内的钥匙。不能够强行打开第一个门。。。 问最多强行打开k(k <= n)个房间的门的情况下,可以全部打开所有门的概率。。 分析

组合数学几类特殊的数,斯特林第一类数,斯特林第二类数,贝尔数

贝尔数 定义: Bn是基数为n的集合的划分方法的数目。集合S的一个划分是定义为S的两两不相交的非空子集的族,它们的并是S。例如B3 = 5因为3个元素的集合{a, b, c}有5种不同的划分方法: {{a}, {b}, {c}}, {{a}, {b, c}}, {{b}, {a, c}}, {{c}, {a, b}}, {{a, b, c}}。 B0是1,因为空集正好有1种划分方法

【数学】填不同的自然数 1/9=1/()+1/()+1/()+1/()+1/()

填不同的自然数 1 9 = 1 ( ) + 1 ( ) + 1 ( ) + 1 ( ) + 1 ( ) \frac{1}{9}=\frac{1}{(\text{ })}+\frac{1}{(\text{ })}+\frac{1}{(\text{ })}+\frac{1}{(\text{ })}+\frac{1}{(\text{ })} 91​=( )1​+( )1​+( )1​+( )1​+(

UVA 10844 - Bloques (第二类斯特灵数)

UVA 10844 - Bloques 题目链接 题意:给定n个数字,问这n个数字能分成子集分成有几种分法 思路:一开始先想了个状态,dp[i][j]表示放i个数字,分成j个集合的方案,那么转移为,从dp[i - 1][j - 1]在多一个集合,和从dp[i - 1][j]有j个位置放,那么转移方程为dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j] *

C语言试题一之计算并输出n(包括n)以内能被5或9整除的所有自然数的倒数之和

📃个人主页:个人主页 🔥系列专栏:C语言试题200例目录 💬推荐一款刷算法、笔试、面经、拿大公司offer神器 👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 请编写函数function,它的功能是:计算并输出n(包括n)以内能被5或9整除的所有自然数的倒数之和。