【题目大意】
给定行数以及每一行的的人数,求方案数,要求从前往后,从左往右身高递增。
【思路分析】
这里没有必要考虑究竟是怎么排的,只要方案数就好啦,然后看到数据范围最大是5行,那么就考虑DP
设$f[a][b][c][d][e]$为第1行站了a个人,第2行站了b个人,第3行站了c个人,第4行站了d个人,第5行站了e个人的方案数
接下来考虑一下转移方程。
首先很明显的条件就是某一个位置在其左边和上面的位置都有人的情况下才可以安排人,这时这个位置的方案数就要加上安排之前的方案数
然后还要注意一下开数组不能直接开$f[31][31][31][31][31]$,那样会爆空间。因为后面一行人数肯定不大于前面一行,所以我们可以只开$f[31][lceil31/2 ceil][lceil31/3 ceil][lceil31/4 ceil][lceil31/5 ceil]$
【代码实现】
1 #include<cstdio> 2 #include<cstring> 3 #define ll long long 4 #define go(i,a,b) for(register int i=a;i<=b;i++) 5 using namespace std; 6 int k,n[6]; 7 ll f[31][31/2+1][31/3+1][31/4+1][31/5+1]; 8 int main(){ 9 while(1){ 10 scanf("%d",&k); 11 if(k==0) return 0; 12 memset(n,0,sizeof(n));memset(f,0,sizeof(f)); 13 go(i,1,k) scanf("%d",&n[i]); 14 f[0][0][0][0][0]=1; 15 go(a,0,n[1]) go(b,0,n[2]) go(c,0,n[3]) go(d,0,n[4]) go(e,0,n[5]){ 16 ll as=f[a][b][c][d][e]; 17 if(a<n[1]) f[a+1][b][c][d][e]+=as; 18 if(b<n[2]&&b<a) f[a][b+1][c][d][e]+=as; 19 if(c<n[3]&&c<b) f[a][b][c+1][d][e]+=as; 20 if(d<n[4]&&d<c) f[a][b][c][d+1][e]+=as; 21 if(e<n[5]&&e<d) f[a][b][c][d][e+1]+=as; 22 } 23 printf("%lld ",f[n[1]][n[2]][n[3]][n[4]][n[5]]); 24 } 25 return 0; 26 }