题目:https://vjudge.net/problem/UVA-12034
思路:将题目换个说法:i匹马占有j个名次,问所有可能的情况
dp[i][j]表示i匹马占有j个名次的组合情况
然后考虑i匹马和i+1匹马的关系(也就是多了一匹马要放在哪个位置)
- 这匹马和前i匹马中至少一匹马的成绩相同(j个名次就有j种情况)
- 这匹马独占了一个成绩(可以放入j个位置)
所以可以得到递推式:dp[i][j] = dp[i-1][j] * j + dp[i-1][j-1] * j
#include<cstdio>
#include<string.h>
using namespace std;
long long dp[1050][1050]; //dp[i][j]表示i只马占有j个名次(i>=j)
long long fac[1000];
void solve()
{
fac[0] = 1; fac[1] = 1;
for (int i = 2; i <= 1000; i++)
fac[i] = (i * fac[i - 1]) % 10056;
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= 1000; i++)
dp[i][1] = 1;
for (int i = 2; i <= 1000; i++)
{
for (int j = 2; j <= i; j++)
{
if (i - 1 >= j)
//前i-1只马用完了j个名次,最后一只马有j种选择; 前面i-1只马用了j-1个名次,(j-1)最后一只马独占一个名次,同样有j种选择
dp[i][j] = (dp[i - 1][j] * j + dp[i - 1][j - 1] * j) % 10056;
else if (i == j)
dp[i][j] = fac[i];
}
}
}
int main()
{
solve();
int T;
scanf("%d", &T);
int k = 1;
while (T--)
{
int n;
scanf("%d", &n);
long long sum = 0L;
for (int i = 1; i <= n; i++)
sum = (sum + dp[n][i]) % 10056;
printf("Case %d: %lld\n", k++, sum);
}
return 0;
}