Acwing 271. 杨老师的照相排列
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Acwing 271. 杨老师的照相排列相关的知识,希望对你有一定的参考价值。
题意:
有n个数分别是从1到n,现在排成k排,每排分别有Ci个数,要求每排每列的都是从小到大,问有多少种方案
题解:
因为每行每列都是单调的,因此我们可以从小到大一次考虑1 ~ n的位置。在任意时刻,已经安排好的位置的数在每一行都是递增关系的(因为我们是从小到大的安排),每个数都插在队尾。我们用一个5元组来表示每行的人数,(a1,a2,a3,a4,a5),ai表示第i行已经安排好的人数,当此时考虑下一步(即再安排一个新人时),我们考虑所有满足如下条件的行号i:
- ai<Ci
- i=1或 a i − 1 > a i a_{i-1}>a_{i} ai−1>ai
从上往下考虑,如果当前行未满,并且当前行人数小于上一行。(如果上一行人数比本行小,那应该优先放在上一行,记住我们是从小到大放置,所以必须顺序放,不然无法保证单调性)
如果满足条件,就对该行进行转移,该行人数+1,加上上一个状态的方案。
我们不需要关心(a1,a2,a3,a4,a5)这些已经排好的具体方案,其描述的轮廓内的合影方案总数就构成一个子问题。
注意直接开数组会爆,使用动态开数组
代码:
#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\\n",a,b);
typedef long long ll;
using namespace std;
//Fe~Jozky
const ll INF_ll=1e18;
const int INF_int=0x3f3f3f3f;
inline ll read(){
ll s=0,w=1ll;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1ll;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10ll+((ch-'0')*1ll),ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);
return s*w;
}
void rd_txt(){
#ifdef ONLINE_JUDGE
#else
freopen("in.txt","r",stdin);
#endif
}
int k;
int a[10];
int main()
{
//rd_txt();
while(cin>>k){
if(k==0)break;
a[1]=a[2]=a[3]=a[4]=a[5]=0;
for(int i=1;i<=k;i++){
cin>>a[i];
}
unsigned int f[a[1]+2][a[2]+2][a[3]+2][a[4]+2][a[5]+2];
memset(f,0,sizeof(f));
f[0][0][0][0][0]=1;
for(int i1=0;i1<=a[1];i1++){
for(int i2=0;i2<=a[2];i2++){
for(int i3=0;i3<=a[3];i3++){
for(int i4=0;i4<=a[4];i4++){
for(int i5=0;i5<=a[5];i5++){
unsigned int x=f[i1][i2][i3][i4][i5];
if(i1<a[1])f[i1+1][i2][i3][i4][i5]+=x;
if(i2<a[2]&&i2<i1)f[i1][i2+1][i3][i4][i5]+=x;
if(i3<a[3]&&i3<i2)f[i1][i2][i3+1][i4][i5]+=x;
if(i4<a[4]&&i4<i3)f[i1][i2][i3][i4+1][i5]+=x;
if(i5<a[5]&&i5<i4) f[i1][i2][i3][i4][i5+1]+=x;
}
}
}
}
}
cout<<f[a[1]][a[2]][a[3]][a[4]][a[5]]<<endl;
}
return 0;
}
以上是关于Acwing 271. 杨老师的照相排列的主要内容,如果未能解决你的问题,请参考以下文章