顺着上篇写的那个Bell数,看到了一些关于Stirling数的题,顺便做了做。
第一类Stirling数:
p个元素分成k个非空环的方案数 s(p,k) = (p-1)*s(p-1,k) + s(p-1,k-1) 可以理解成由p-1个元素分成k个环的情况下插入一个元素的方案数,加上一个单独成一个环,其余的元素分成k-1个环的方案。
第二类Stirling数:
p个元素分成k个非空集合的方案数 s(p,k) = k*s(p-1,k) + s(p-1,k-1) 可以理解成由p-1个元素分成k个集合的情况下选择一个集合插入最后的那个元素,加上一个元素单独一个集合,其余元素分成k-1个集合的方案数。
两者边界都是s(0,0)=1
题目:hdu 3625
属于第一类Stirling数,由于第一扇门不能被破坏,所有方案数为 sigma (s(n,i) - s(n-1,i-1) ) i from 1 to k
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
#define maxn 21
long long fac[maxn];
long long s[maxn][maxn];
void init()
{
memset(s,0,sizeof(s));
s[0][0]=1;
for(int i=1;i<maxn;i++)
for(int j=1;j<=i;j++)
s[i][j]=(i-1)*s[i-1][j]+s[i-1][j-1];
fac[0]=1;
for(int i=1;i<maxn;i++)
fac[i]=fac[i-1]*i;
}
long long solve(int n,int k)
{
long long ans=0;
for(int i=1;i<=k;i++)
ans+=s[n][i]-s[n-1][i-1];
return ans;
}
int main()
{
init();
int t;
scanf("%d",&t);
while(t--)
{
int n,k;
scanf("%d%d",&n,&k);
printf("%.4lf\n",1.0*solve(n,k)/fac[n]);
}
return 0;
}
题目:hdu 2512
求的跟那道 Bell 一样的,不过范围小得多。
// 直接用Bell数
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>
using namespace std;
#define mod 1000
#define maxn 2001
long long c[maxn][maxn];
long long b[maxn];
void init()
{
memset(c,0,sizeof(c));
c[0][0]=1;
for(int i=0;i<maxn;i++)
{
c[i][0]=c[i][i]=1;
for(int j=1;j<i;j++)
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
b[0]=1;
for(int i=1;i<maxn;i++)
{
b[i]=0;
for(int j=0;j<i;j++)
b[i]=(b[i]+c[i-1][j]*b[j])%mod;
}
}
int main()
{
init();
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
printf("%I64d\n",b[n]);
}
return 0;
}
或者用第二类Stirling数(其本质是一样的)
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>
using namespace std;
#define mod 1000
#define maxn 2001
long long s[maxn][maxn];
long long b[maxn];
void init()
{
memset(s,0,sizeof(s));
s[0][0]=1;
for(int i=1;i<maxn;i++)
{
for(int j=0;j<=i;j++)
s[i][j]=(j*s[i-1][j]+s[i-1][j-1])%mod;
}
b[0]=1;
for(int i=1;i<maxn;i++)
{
b[i]=0;
for(int j=0;j<=i;j++)
b[i]=(b[i]+s[i][j])%mod;
}
}
int main()
{
init();
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
printf("%I64d\n",b[n]%mod);
}
return 0;
}
题目:light 1326 - Race
思路:裸的第二类Stirling数+全排列
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
using namespace std;
#define maxn 1010
#define mod 10056
long long fac[maxn];
long long s[maxn][maxn];
void init()
{
fac[0]=1;
for(int i=1;i<maxn;i++)
fac[i]=(fac[i-1]*i)%mod;
memset(s,0,sizeof(s));
s[0][0]=1;
for(int i=1;i<maxn;i++)
{
for(int j=1;j<=i;j++)
s[i][j]=(j*s[i-1][j]+s[i-1][j-1])%mod;
}
}
long long solve(int n)
{
long long ans=0;
for(int i=1;i<=n;i++)
ans=(ans+s[n][i]*fac[i])%mod;
return ans;
}
int main()
{
init();
int t;
scanf("%d",&t);
for(int cas=1;cas<=t;cas++)
{
int n;
scanf("%d",&n);
printf("Case %d: %lld\n",cas,solve(n));
}
return 0;
}