目标
求∑i=0nik\sum_{i=0}^ni^ki=0∑nik
前置技能
第一类斯特林数
第一类斯特林数s(n,m)s(n,m)s(n,m)定义为有n个人,编号分别为1-n,排成m个循环排列的方案数。
递推式:s(n,m)=s(n−1,m−1)+(n−1)∗s(n−1,m)s(n,m)=s(n-1,m-1)+(n-1)*s(n-1,m)s(n,m)=s(n−1,m−1)+(n−1)∗s(n−1,m)
证明:若第n个人自己排成一个循环排列,则方案数为s(n−1,m)s(n-1,m)s(n−1,m);若第n个人加入到原来的循环排列中,则可以放在任意一个人的左边,方案数为(n−1)∗s(n−1,m)(n-1)*s(n-1,m)(n−1)∗s(n−1,m)
另一种形式
众所周知,Cnk表示从n件物品中选出k件的方案数,众所周知,C_n^k表示从n件物品中选出k件的方案数,众所周知,Cnk表示从n件物品中选出k件的方案数,P_n^k表示从n件物品中选出k个排列的方案数表示从n件物品中选出k个排列的方案数表示从n件物品中选出k个排列的方案数
显然有Cnk=Pnkk!C_n^k=\frac{P_n^k}{k!}Cnk=k!Pnk
根据定义我们可以得到Pnk=n∗(n−1)∗...∗(n−k+1)P_n^k=n*(n-1)*...*(n-k+1)Pnk=n∗(n−1)∗...∗(n−k+1)
展开后可得Pnk=S(k,k)∗nk−S(k,k−1)∗nk−1...P_n^k=S(k,k)*n^k-S(k,k-1)*n^{k-1}...Pnk=S(k,k)∗nk−S(k,k−1)∗nk−1...
所以有Pnk=∑i=0k(−1)k−i∗s(k,i)∗niP_n^k=\sum_{i=0}^k(-1)^{k-i}*s(k,i)*n^iPnk=i=0∑k(−1)k−i∗s(k,i)∗ni
这个才是第一类斯特林数的定义。
所以第一类斯特林数S就是排列数公式的展开式的系数,也是如上所述的那个东西。
第一类斯特林数的递推
边界条件:s(p,0)=0(p>0),s(p,p)=1(p>=0)s(p,0)=0(p>0),s(p,p)=1(p>=0)s(p,0)=0(p>0),s(p,p)=1(p>=0)
一个小结论
∑i=0nCik=Cn+1k+1\sum_{i=0}^nC_i^k=C_{n+1}^{k+1}i=0∑nCik=Cn+1k+1
证明:因为Cn+1k+1=Cnk+Cnk+1C_{n+1}^{k+1}=C_n^{k}+C_n^{k+1}Cn+1k+1=Cnk+Cnk+1,等式两边可以同时把CnkC_n^kCnk消掉,然后就又得到了一个相同形式的式子。所以通过归纳法便可以证明这个结论。
求自然数幂和
我们设Sk(n)=∑i=0nikS_k(n)=\sum_{i=0}^ni^kSk(n)=i=0∑nik
根据第一类斯特林数的定义,有Cnk=Pnkk!=∑i=0k(−1)k−i∗s(k,i)∗nik!C_n^k=\frac{P_n^k}{k!}=\frac{\sum_{i=0}^k(-1)^{k-i}*s(k,i)*n^i}{k!}Cnk=k!Pnk=k!∑i=0k(−1)k−i∗s(k,i)∗ni
把式子中的nkn^knk提出来,得nk=Cnk∗k!−∑i=0k−1(−1)k−i∗s(k,i)∗nin^k=C_n^k*k!-\sum_{i=0}^{k-1}(-1)^{k-i}*s(k,i)*n^ink=Cnk∗k!−i=0∑k−1(−1)k−i∗s(k,i)∗ni
那么Sk(n)=∑i=0nikS_k(n)=\sum_{i=0}^ni^kSk(n)=i=0∑nik
=∑i=0n(Cik∗k!−∑j=0k−1(−1)k−j∗s(k,j)∗ij)=\sum_{i=0}^n(C_i^k*k!-\sum_{j=0}^{k-1}(-1)^{k-j}*s(k,j)*i^j)=i=0∑n(Cik∗k!−j=0∑k−1(−1)k−j∗s(k,j)∗ij)
=k!∗∑i=0nCik−∑i=0n∑j=0k−1(−1)k−j∗s(k,j)∗ij=k!*\sum_{i=0}^nC_i^k-\sum_{i=0}^n\sum_{j=0}^{k-1}(-1)^{k-j}*s(k,j)*i^j=k!∗i=0∑nCik−i=0∑nj=0∑k−1(−1)k−j∗s(k,j)∗ij
=k!∗Cn+1k+1−∑j=0k−1(−1)k−j∗s(k,j)∗Sj(n)=k!*C_{n+1}^{k+1}-\sum_{j=0}^{k-1}(-1)^{k-j}*s(k,j)*S_j(n)=k!∗Cn+1k+1−j=0∑k−1(−1)k−j∗s(k,j)∗Sj(n)
=Pn+1k+1k+1−∑j=0k−1(−1)k−j∗s(k,j)∗Sj(n)=\frac{P_{n+1}^{k+1}}{k+1}-\sum_{j=0}^{k-1}(-1)^{k-j}*s(k,j)*S_j(n)=k+1Pn+1k+1−j=0∑k−1(−1)k−j∗s(k,j)∗Sj(n)
于是就可以愉快地O(k2)O(k^2)O(k2)递推Sk(n)S_k(n)Sk(n)啦。边界条件S1(n)=n∗(n+1)2S_1(n)=\frac{n*(n+1)}{2}S1(n)=2n∗(n+1)
因为Pn+1k+1=(n+1)∗n∗(n−1)∗...∗(n−k+1)P_{n+1}^{k+1}=(n+1)*n*(n-1)*...*(n-k+1)Pn+1k+1=(n+1)∗n∗(n−1)∗...∗(n−k+1),而连续k+1个数中必然有一个是k+1的倍数,所以在用这种方法求自然数幂和时,由于不存在除法,所以并不用考虑模数是什么。
代码
int get_sum(int n)
{
sum[1]=(LL)n*(n+1)/2%MOD;
for (int i=2;i<=k;i++)
{
sum[i]=1;
for (int j=0;j<i+1;j++)
if ((LL)(n-j+1)%(i+1)==0) sum[i]=(LL)(n-j+1)/(i+1)*sum[i]%MOD;
else sum[i]=(LL)(n-j+1)*sum[i]%MOD;
for (int j=1;j<i;j++)
if ((i-j)%2==0) (sum[i]-=(LL)s[i][j]*sum[j]%MOD)%=MOD;
else (sum[i]+=(LL)s[i][j]*sum[j]%MOD)%=MOD;
}
return (sum[k]+MOD)%MOD;
}