典中典之第二类斯特林数
作者:互联网
第二类斯特林数:将 \(n\) 个物品放进 \(m\) 个不区分的盒子的方案数,记为 \(S(n,m)\)。
\(n^2\) 递推公式:\(S(n,m)=S(n-1,m-1)+m\cdot S(n-1,m)\).
附代码:
s[0][0]=1;
for(int i=1;i<=n;++i)
for(int j=1;j<=i;++j)
s[i][j]=add(s[i-1][j-1],mul(s[i-1][j],j));
第二类斯特林数的卷积公式:
\[S(n,m)=\sum_{k=0}^m \frac{(-1)^k}{k!}\frac{(m-k)^n}{(m-k)!} \]斯特林数转下降幂公式:
\[x^k=\sum_{i=0}^kS(k,i)x^{\underline i} \]又已知一常见组合公式(证明展开即可):
\[\binom{n}{x} x^{\underline i}=\binom{n-i}{x-i}n^{\underline i} \]将以上两式合并则有:
\[\binom{n}{x}x^k = \sum_{i=0}^k S(k,i)\binom{n-i}{x-i} n^{\underline i} \]对于枚举 \(x\) 的题目,一般只需交换求和号后将后面的组合数用二项式定理合并成 \(n-i\) 次多项式即可,这样可以将时间复杂度由 \(n\) 降到 \(k\)。
例1:CF932E Team Work
从 \(n\) 个物品中挑任意个,挑 \(x\) 个的价值为 \(x^k\)。求所有方案的价值和。\(n\le 10^9, k\le 5000\).
即求
\[\sum_{x=0}^n \binom{n}{x} x^k \]由前文式子可得
\[=\sum_{x=0}^n \sum_{i=0}^k S(k,i)\binom{n-i}{x-i} n^{\underline i} \]交换求和号
\[=\sum_{i=0}^{\min(k,n)} S(k,i)n^{\underline i}\sum_{x=i}^{n} \binom{n-i}{x-i} \]改为枚举 \(x-i\)
\[=\sum_{i=0}^{\min(k,n)} S(k,i)n^{\underline i}\sum_{x=0}^{n-i} \binom{n-i}{x} \]后半部分求和用二项式定理合并,即为
\[=\sum_{i=0}^{\min(k,n)} S(k,i)n^{\underline i} 2^{n-i} \]\(O(k^2)\) 预处理第二类斯特林数后 \(O(k)\) 求解即可。
#include<bits/stdc++.h>
using namespace std;
const int N=5005,Mod=1e9+7;
#define mul(x,y) (1ll*(x)*(y)%Mod)
inline int add(int x, int y)
{
return (x+y>=Mod?x+y-Mod:x+y);
}
inline int po(int x, long long y)
{
int r=1;
for(;y;y>>=1,x=mul(x,x)) if(y&1) r=mul(r,x);
return r;
}
int s[N][N],n,m,k;
int main()
{
int n,k; scanf("%d%d",&n,&k);
s[0][0]=1;
for(int i=1;i<=k;++i)
for(int j=1;j<=i;++j)
s[i][j]=add(s[i-1][j-1],mul(s[i-1][j],j));
int ans=0;
for(int i=0,b=1,c=po(2,n),iv=po(2,Mod-2);i<=min(n,k);++i)
{
int t=mul(s[k][i],mul(b,c));
ans=add(ans,t);
b=mul(b,n-i), c=mul(c,iv);
}
printf("%d\n",ans);
}
例2:CF1716F Bags with Balls
有 \(n\) 个盒子,每个盒子里放着编号 \(1\sim m\) 的球。每次从每个盒子里分别抽取 1 个球,令抽到的编号为奇数的球的个数为 \(x\),则价值为 \(x^k\)。求所有可能方案的价值之和。\(T\) 组数据,\(n,m<998244353, k\le 2000\).
即为求
\[\sum_{x=0}^n x^k \binom{n}{x} \lceil\frac{m}{2}\rceil^x \lfloor \frac{m}{2}\rfloor ^ {n-x} \]由上文结论易推得
\[=\sum_{i=0}^{\min(k,n)} S(k,i)n^{\underline i}\sum_{x=0}^{n-i} \binom{n-i}{x} \lceil\frac{m}{2}\rceil^{x+i} \lfloor \frac{m}{2}\rfloor ^ {n-i-x} \]提取一个 \(\lceil\frac{m}{2}\rceil^i\),后面用二项式定理合并,即为 \(m^{n-i}\)。
\[=\sum_{i=0}^{\min(k,n)} S(k,i)n^{\underline i} \lceil\frac{m}{2}\rceil^i m^{n-i} \]线性计算即可。复杂度 \(O(k^2+Tk)\)。
#include<bits/stdc++.h>
using namespace std;
const int N=2022,Mod=998244353;
#define mul(x,y) (1ll*(x)*(y)%Mod)
inline int add(int x, int y)
{
return (x+y>=Mod?x+y-Mod:x+y);
}
inline int po(int x, long long y)
{
int r=1;
for(;y;y>>=1,x=mul(x,x)) if(y&1) r=mul(r,x);
return r;
}
int s[N][N],n,m,k;
void Init()
{
const int n=2000;
s[0][0]=1;
for(int i=1;i<=n;++i)
for(int j=1;j<=i;++j)
s[i][j]=add(s[i-1][j-1],mul(s[i-1][j],j));
}
int main()
{
Init();
int T; scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&k);
const int o=(m-1)/2+1;
int ans=0;
for(int i=0,b=1,c=1,d=po(m,n),iv=po(m,Mod-2);i<=min(n,k);++i)
{
int t=mul(s[k][i],mul(mul(b,c),d));
ans=add(ans,t);
b=mul(b,n-i), c=mul(c,o), d=mul(d,iv);
}
printf("%d\n",ans);
}
}
待填坑。
标签:第二类,frac,斯特林,sum,int,典中典,binom,underline,Mod 来源: https://www.cnblogs.com/farway17/p/16574471.html