题意:
有k个比赛,n个人,现在要求k个比赛每一个只能参加一个人,每一个人至少参加
一个比赛。问所有满足条件的排列种类数目。
思路:
以后遇到这种题要考虑怎么定义状态,怎么递推。
dp[i][j]代表的意义是i场比赛j个人满足条件的种类数目。
状态定义之后,递推需要分情况,当i小于j时dp[i][j] = 0,当i=j时dp[i][j] = i!。
当j = 1时,dp[i][j] = 1;上边很容易推出来。但是还有很重要的一种当i 大于 j时,
dp[i][j] = j*dp[i-1][j-1] + j*dp[i-1][j],其中j*dp[i-1][j-1]代表i-1个比赛j-1个人刚
好选择了,那么剩下的一个比赛第j个人选择(有j中情况),j*dp[i-1][j]代表着i-1场
比赛j个人已经都选择了,那么剩下的一场比赛直接任意一个选择就行。
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
const int MOD = 1000000007;
LL dp[1001][1001];
void solve()
{
for(int i = 1;i <= 1000; i++) {
for(int j = 1;j <= 1000; j++) {
if(j == 1) dp[i][j] = 1;
else if(i == j) {
int temp = j;
LL ans = 1;
while(temp) {
ans *= temp;
ans %= 1000000007;
temp--;
}
dp[i][j] = ans;
}
else if(i < j) {
dp[i][j] = 0;
}
else {
dp[i][j] = ((j*dp[i-1][j-1])%1000000007 + (j*dp[i-1][j])%1000000007)%1000000007;
}
}
}
}
int main()
{
freopen("galactic.in","r",stdin);
int t;
solve();
scanf("%d",&t);
while(t--) {
int a,b;
scanf("%d%d",&a,&b);
if(b > a)
printf("0\n");
else
printf("%I64d\n",dp[a][b]);
}
}