题目大意:给出n,p和r,表示有n个长短不一的人排队,从前面看可以看到p个人,从后面看可以看到r个人,问这种队列有多少种。
解题思路:这题前几天看到的,当时一直想这说每次加入一个最高的,结果发现加进的最高个站哪里都是问题,然后今天灵光一闪,想到可以每次加入最矮的,这样他站在最前面的话,p就加1(挡不住任何人);站在队末尾的话,r就加1;站在队伍中间的任何位置,都会被挡住,p,r不变。
然后状态转移方程就出来了,dp[i][j][k] = dp[i - 1][j - 1][k] + dp[i - 1][j][k - 1] + ( i - 2) * dp[i - 1][j][k].
#include <stdio.h>
#include <string.h>
const int N = 20;
long long dp[N][N][N];
void init() {
memset(dp, 0, sizeof(dp));
dp[1][1][1] = 1;
for (int i = 2; i <= 13; i++) {
for (int j = 1; j <= i; j++) {
int top = i - j + 1;
for (int k = 1; k <= top; k++)
dp[i][j][k] = dp[i - 1][j - 1][k] + dp[i - 1][j][k - 1] + (i - 2) * dp[i - 1][j][k];
}
}
}
int main () {
int cas, n, p, r;
scanf("%d", &cas);
init();
while (cas--) {
scanf("%d%d%d", &n, &p, &r);
printf("%lld\n", dp[n][p][r]);
}
return 0;
}