问题描述:
有N个学生合影,站成左端对齐的 k排,每排分别有 N1,N2,N3,N4,……Nk个人,第一排站在最后面,第k排站在最前面。学生的身高各不相同,把他们的升高依次标记为1,2,……N。在合影时要求每一排从左到右身高递减,每一列从前到后也递减,问一共有多少种合影位置方案。
输入样例:
3
3 2 1
输出样例:
16
数据范围:
N<=30,k<=5
题解:
考虑按照顺序插入学生,即从大到小的顺序。所以每一个学生要进入就必须放在右端或下端,对于插入对象为一行时,即每一个同学插入某一行,该行应满足,未满,当前人数小于前一行的人数或者是第一行。所以可以以每行的人数建立状态。
f[x1][x2][x3][x4][x5]表示第一行有x1个人…… 的方案数。当插入一人到一行中时,这一维+1 方案数*2;
code:
#include<bits/stdc++.h>
using namespace std;
int n;
int a[100];
unsigned int f[31][31][31][31][31];
void work()
{
f[0][0][0][0][0]=1;
int a1=a[1],a2=a[2],a3=a[3],a4=a[4],a5=a[5];
for(int x1=0;x1<=a1;x1++)
for(int x2=0;x2<=a2;x2++)
for(int x3=0;x3<=a3;x3++)
for(int x4=0;x4<=a4;x4++)
for(int x5=0;x5<=a5;x5++)
{
if(x1<a1) f[x1+1][x2][x3][x4][x5]+=f[x1][x2][x3][x4][x5];
if(x2<a2 && x2<x1) f[x1][x2+1][x3][x4][x5]+=f[x1][x2][x3][x4][x5];
if(x3<a3 && x3<x2) f[x1][x2][x3+1][x4][x5]+=f[x1][x2][x3][x4][x5];
if(x4<a4 && x4<x3) f[x1][x2][x3][x4+1][x5]+=f[x1][x2][x3][x4][x5];
if(x5<a5 && x5<x4) f[x1][x2][x3][x4][x5+1]+=f[x1][x2][x3][x4][x5];
}
printf("%lld\n",f[a1][a2][a3][a4][a5]);
}
int main()
{
freopen("i.in","r",stdin);
freopen("i.out","w",stdout);
while(scanf("%d",&n)!=EOF)
{
if(n==0) break;
memset(a,0,sizeof(a));
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
work();
}
return 0;
}