链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4513

题意:

有高为1, 2, 3,…, n的杆子各一根排成一行。从左边能看到L根,从右边能看到R根,求有多少种可能。

分析:

设d(i,j,k)表示让高度为1~i的杆子排成一行,从左边能看到j根,从右边能看到k根的方案数(设i≥2)。
按照从大到小的顺序安排各个杆子。假设已经安排完高度为2~i的杆子,
那么高度为1的杆子不管放哪里都不会挡住任何一根杆子。有如下3种情况。
情况1:插到最左边,则从左边能看到它,从右边看不见(因为i≥2)。
情况2:如果插到最右边,则从右边能看到它,从左边看不见。
情况3(有i-2个插入位置):插到中间,则不管从左边还是右边都看不见它。
在第一种情况下,高度为2~i的那些杆子必须满足:从左边能看到j-1根,从右边能看到k根,
因为只有这样,加上高度为1的杆子之后才是“从左边能看到j根,从右边能看到k根”。
虽然状态d(i,j,k)表示的是“让高度为1~i的杆子……”,而现在需要把高度为2~i+1的杆子排成一行,
但是不难发现:其实杆子的具体高度不会影响到结果,只要有i根高度各不相同的杆子,
从左从右看分别能看到j根和k根,方案数就是d(i,j,k)。换句话说,情况1对应的方案数是d(i-1,j-1,k)。
类似地,情况2对应的方案数是d(i-1,j,k-1),而情况3对应的方案数是d(i-1,j,k)*(i-2)。
这样,就得到了如下递推式:d(i,j,k) = d(i-1,j-1,k) + d(i-1,j,k-1) + d(i-1,j,k)*(i-2)。

代码:

 import java.io.*;
import java.util.*; public class Main {
static final int UP = 20 + 1;
static long d[][][] = new long[UP][UP][UP]; static void constant() {
d[1][1][1] = 1;
for(int n = 2; n < UP; n++) {
for(int L = 1; L <= n; L++) {
for(int R = 1; R <= n; R++) {
d[n][L][R] += d[n-1][L-1][R];
d[n][L][R] += d[n-1][L][R-1];
d[n][L][R] += d[n-1][L][R] * (n-2);
}
}
}
} public static void main(String args[]) {
Scanner cin = new Scanner(new BufferedInputStream(System.in));
constant(); int T = cin.nextInt();
while(T --> 0) {
int n = cin.nextInt();
int L = cin.nextInt();
int R = cin.nextInt();
System.out.println(d[n][L][R]);
}
cin.close();
}
}
05-08 08:13