自然数幂和——第一类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 + ;
const int maxk = + ;
ll n, k; ll stir[maxk][maxk];
void init()
{
stir[][] = stir[][] = ;
for(int i = ;i < maxk;i++)
for(int j = ;j <= i;j++)
stir[i][j] = (stir[i-][j-] + (i-)*stir[i-][j]) % mod;
} ll S[maxk]; //S[i]表示前n项的i次方之和
ll cal()
{
n %= mod;
S[] = (n+) * n / % mod; //假设 k>=1
for(int i = ;i <= k;i++)
{
//计算前面一坨
ll prod;
if(i > n) prod = ;
else
{
ll kk = i+;
prod = ;
for(ll j = ;j <= i;j++)
{
ll tmp = n+-j;
if(tmp % (i+) == ) prod = prod * (tmp/(i+)) % mod;
else prod = prod * tmp % mod;
}
} ll tmp = , sig;
for(int j = ;j < i;j++)
{
sig = (j+i)& ? - : ;
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 ;
}
第二类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 + ;
const int maxk = + ;
ll n, k; ll stir[maxk][maxk];
void init()
{
stir[][] = stir[][] = ;
for(int i = ;i < maxk;i++)
for(int j = ;j <= i;j++)
stir[i][j] = (stir[i-][j-] + j*stir[i-][j]) % mod;
} ll cal()
{
n %= mod;
ll sum = ;
for(int i = ;i <= k;i++)
{
ll prod;
if(i > n) prod = ;
else
{
prod = ;
for(int j = ;j <= i;j++)
{
ll tmp = n+-j;
if(tmp % (i+) == ) tmp /= (i+);
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 ;
}
参考链接:
1. https://www.cnblogs.com/Zerokei/p/9726879.html
2. https://blog.csdn.net/lyd_7_29/article/details/75041818
自然数幂和——第一类Stirling数和第二类Stirling数的更多相关文章
- 第一类和第二类Stirling数
做了老是忘…… 实际问题: 找维基百科.百度百科…… 第一类Stirling数 n个元素构成m个圆排列 S(n,m)=S(n-1,m-1)+(n-1)*S(n-1,m) 初始 S(0,0)=1 S(n ...
- [总结] 第二类Stirling数
上一道例题 我们来介绍第二类Stirling数 定义 第二类Stirling数实际上是集合的一个拆分,表示将n个不同的元素拆分成m个集合的方案数,记为 或者 .和第一类Stirling数不同的是,集合 ...
- (转) [组合数学] 第一类,第二类Stirling数,Bell数
一.第二类Stirling数 定理:第二类Stirling数S(p,k)计数的是把p元素集合划分到k个不可区分的盒子里且没有空盒子的划分个数. 证明:元素在哪些盒子并不重要,唯一重要的是各个盒子里装的 ...
- 自然数幂求和——第二类Strling数
这个问题似乎有很多种求法,但感觉上第二类Strling数的做法是最方便的. 问题 求下面这个式子: ∑i=0nik\sum_{i=0}^n i^ki=0∑nik nnn的范围可以很大. 第二类Str ...
- 第二类Stirling数
第二类斯特林数 第二类Stirling数:S2(p, k) 1.组合意义:第二类Stirling数计数的是把p个互异元素划分为k个非空集合的方法数 2.递推公式: S2(0, 0) = 1 S2(p, ...
- Codeforces 622F The Sum of the k-th Powers ( 自然数幂和、拉格朗日插值法 )
题目链接 题意 : 就是让你求个自然数幂和.最高次可达 1e6 .求和上限是 1e9 分析 : 题目给出了最高次 k = 1.2.3 时候的自然数幂和求和公式 可以发现求和公式的最高次都是 k+1 ...
- UVA766 Sum of powers(1到n的自然数幂和 伯努利数)
自然数幂和: (1) 伯努利数的递推式: B0 = 1 (要满足(1)式,求出Bn后将B1改为1 /2) 参考:https://en.wikipedia.org/wiki/Bernoulli_numb ...
- lightOJ 1326 Race(第二类Stirling数)
题目链接:http://lightoj.com/volume_showproblem.php?problem=1326 题意:有n匹马赛跑.问有多少种不同的排名结果.可以有多匹马的排名相同. 思路:排 ...
- 【BZOJ】3453: tyvj 1858 XLkxc 拉格朗日插值(自然数幂和)
[题意]给定k<=123,a,n,d<=10^9,求: $$f(n)=\sum_{i=0}^{n}\sum_{j=1}^{a+id}\sum_{x=1}^{j}x^k$$ [算法]拉格朗日 ...
随机推荐
- C++ STL学习总结
1.vector //最好给它一个初始化大小 #include <iostream> #include <vector> using namespace std; int ma ...
- 在local模式下的spark程序打包到集群上运行
一.前期准备 前期的环境准备,在Linux系统下要有Hadoop系统,spark伪分布式或者分布式,具体的教程可以查阅我的这两篇博客: Hadoop2.0伪分布式平台环境搭建 Spark2.4.0伪分 ...
- k8s--yml文件
- 服务注册发现(一) Consul 简介及 windows版本的安装与部署
Consul是一个用来实现分布式系统的服务发现与配置的开源工具.他主要由多个组成部分: 服务发现:客户端通过Consul提供服务,类似于API,MySQL,或者其他客户端可以使用Consul发现服务的 ...
- 【夯实基础】- Integer.valueof()和Integer.parseInt()的区别
今天在看公司代码的时候,看到有人在将 String 转为 int 时,用到了Integer.parseInt(String s)方法,我一直用的是Integer.valueOf(String s)方法 ...
- VUE基础回顾2
1.响应式 vue修改了每个添加到data上的对象,当该对象发生变化时vue会收到通知,从而实现响应式.对象的每个属性都会被替换为getter,setter方法. 有两种方式实现data对象的监听 ( ...
- tensorflow遇到ImportError: Could not find 'cudart64_100.dll'错误解决
在安装tensorflow的时候,使用import tensorflow出现了找不到dll文件的错误,参考了很多博客和stackflow的解决方案,发现其中只说了版本号不匹配,但是没有具体说明什么样的 ...
- POSIX 使用互斥量和条件变量实现生产者/消费者问题
boost的mutex,condition_variable非常好用.但是在Linux上,boost实际上做的是对pthread_mutex_t 和pthread_cond_t的一系列的封装.因此通过 ...
- 雪妖现世:给SAP Fiori Launchpad增添雪花纷飞的效果
1995年7月,台湾大宇公司发布了一款国产单机角色扮演游戏神作:<仙剑奇侠传1>,所谓"一包烟,一杯茶",就能在电脑面前坐一整天. 这么经典的游戏Jerry当然已经通关 ...
- idea 启动项目报错,more than one fragment with the name [spring web] was found
这是由于idea导入项目的时候有多个模块,并且有多个web.xml导致的,先删除对应的模块,后启动即可. 另外也有可能是spring的jar冲突,把冲突的jar删除即可.