小结:
因为这个分类是分类在递推中的,所以想法理所当然应该往递推的方向去走,首先能想到的是从低到高依次摆放杆子,不过尝试过就知道了,做法远比想象中复杂,然后就尝试了下依次从高往低排,视野一下子就开阔了。
然后就是怎么实现递推了,令f(i,j,k)代表从左边看有i根杆子,从右边看有j根杆子,已经放置的杆子有k根的情况,由于,看到的杆子的根数只和杆子的相对高度有关,而和杆子的绝对高度无关。那么,当放入一根比已有的杆子长度都短的杆子时,只可能有3种情况:
(1)杆子放在所有杆子的最左端,造成的结果是从左边可以看见的杆子数加1,而从右边能看见的杆子数目不变。
(2)杆子放在所有杆子的最右端,造成的结果是从右边可以看见的杆子数加1,而从左边能看见的杆子数目不变。
(3)杆子放在任意中间位置,由于放入的杆子比所有的杆子的高度要低,所以从左,右两边能看见得杆子数目不变。
因此,
递推方程为:f(i,j,k)=f(i-1,j,k-1)+f(i,j-1.k)+f(i,j,k-1)。
以下是AC代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<malloc.h>
using namespace std;
typedef long long ll;
ll recur[50][50][50];
int main()
{
int n,l,r;
int t;
scanf("%d",&t);
for(int m=1;m<=t;m++)
{
scanf("%d%d%d",&n,&l,&r);
memset(recur,0,sizeof(recur));
recur[1][1][1]=1;
recur[2][1][2]=1;
recur[1][2][2]=1;
for(int i=3;i<=n;i++)
{
for(int j=1;j<=l;j++)
for(int k=1;k<=r;k++)
{
if(j==1&&k==1)
continue;
recur[j][k][i]=recur[j-1][k][i-1]+recur[j][k-1][i-1]+recur[j][k][i-1]*(i-2);
}
}
printf("%lld\n",recur[l][r][n]);
}
return 0;
}