该题用到了DP的思想,递推出所有可能情况 。
要想维护所有状态,求出要求的情况,那么显然要维护三个量:几根杆子(DP的序)、从左边看杆子的数量、从右边看杆子的数量 。
所以状态表示也要增加相应的维度,用d[i][j][k]表示前i根杆子,从左边看有j根,从右边看有k根的可能情况 。
接下来就要想好如何转移状态了 : 当前状态肯定要依赖于上一阶段的状态,那么我们不妨想:当前状态与上一状态的不同之处是要将第i根杆子插入前i-1根杆子中,那么有几种可能情况呢? 显然是三种 : 1.插到最左边,那么从左边看杆子数加一(因为杆子是从大到小插入的)。2.插到最右边,那么右边的杆子数加一。3.插到中间,我们假设i从2开始,那么将有i-2种插法,而且不会改变从两边看到的杆子数。
第三步,确定好递推的边界 :因为i从2开始,所以它所依赖的边界是i为1时的情况,当i为1时无论从左边还是右边都只能看到一根,所以边界为d[1][1][1] = 1;其他值为0 。
另外要开long long 。
细节参见代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 25;
int T,n,m,l,r;
ll d[maxn][maxn][maxn];
int main() {
scanf("%d",&T);
while(T--) {
scanf("%d%d%d",&n,&l,&r);
memset(d,0,sizeof(d));
d[1][1][1] = 1;
for(int i=2;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
d[i][j][k] = d[i-1][j-1][k] + d[i-1][j][k-1] + d[i-1][j][k]*(i-2);
printf("%lld\n",d[n][l][r]);
}
return 0;
}