题意是一个人有姓和名,都是有n个字符组成的。要求一个人的姓何名不能出现相同的字符。现在有m个字符,问你一共可以有多少不同的人。
首先我们先学习下斯特林数。
第一类Stirling数s(p,k)
第一类Stirling数的含义:将p个物体排成k个非空循环排列的种类数。
s(p,k)=s(p-1,k-1)+s(p-1,k)*(p-1)。1<=k<=p-1 s(p,0)=0,s(p,p)=1
递推关系的说明:
考虑第p个物品,p可以单独构成一个非空循环排列,这样前p-1种物品构成k-1个非空循环排列,方法数为s(p-1,k-1);
也可以前p-1种物品构成k个非空循环排列,而第p个物品插入第i个物品的左边,这有(p-1)*s(p-1,k)种方法。
第二类Stirling数s(p,k)
含义:将p个物体划分成k个不可分辨的集合的方法数。
k!s(p,k)是将p个物体划分成k个可分别(有编号)的集合的方法数。
s(p,k)=s(p-1,k-1)+s(p-1,k)*k; s(p,p)=1;s(p,0)=0;
那么对于这道题,我们可以枚举姓和名的字符数分别为i,j;
那么答案为C(m,i)*F(n,i)*C(m-i,j)*F(n,j)。F(n,i)表示在这n个位置中放i个字符的方法数。可以知道F(n,i)=i!*s(n,i)
也可以根据容斥原理
F(n,x)=xn−(x1)(x−1)n+(x2)(x−2)n−(x3)(x−3)n+...
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll s[2010][2010],C[2010][2010],pow[2010];
void init()
{
memset(s,0,sizeof(s));
s[1][1]=1;
for(int i=2;i<=2000;i++)
{
for(int j=1;j<=i;j++)
{
s[i][j]=j*s[i-1][j]+s[i-1][j-1];
if(s[i][j]>=mod)
s[i][j]%=mod;
}
}
C[0][0]=1;C[1][0]=1;C[1][1]=1;
for(int i=2;i<=2000;i++)
{
for(int j=0;j<=i;j++)
{
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
}
}
void powd()
{
pow[1]=1;
for(int i=2;i<=2000;i++)
{
pow[i]=(pow[i-1]*i)%mod;
}
}
int main()
{
int t,n,m;
scanf("%d",&t);
init();
powd();
while(t--)
{
scanf("%d%d",&n,&m);
ll ans=0,cnt=0;
for(int i=1;i<m;i++)
{
for(int j=1;j<=m-i;j++)
{
ll a=((C[m][i]*s[n][i])%mod*pow[i])%mod;
ll b=((C[m-i][j]*s[n][j])%mod*pow[j])%mod;
ans+=(a*b)%mod;
ans=ans%mod;
}
}
printf("%I64d\n",ans);
}
}