若干人左对齐站成最多5行,给定每行站多少个,列数从第一排开始往后递减。要求身高从每排从左到右递增(我将题意篡改了便于理解233),每列从前向后递增。每个人身高为1...n(n<=30)中的一个数(互不不同)。求可行方案数。(地址点我qwq);


做了lyd书dp这一章的第一题,就不会qwq。。果然菜的人还是永远菜啊,注定翻不了身。

lyd的书上讲到了dp的方法,不是很理解。后来想通了,发现自己想的时候也想到了这一点转化,但是又很快把他抛弃掉了。。冏。

上面所谓的转化就是说,我本来安排人去排列,是无序的,显然也不好dp,因为高度不定,选了哪些也不知道,对后续状态有影响,所以要转化为有序的dp。有没有觉得很熟悉?BZOJ1079[SCOI2008]着色方案[组合计数DP]这里就是将无序的排列改为有序的插入。

对于要求从前面的一些状态中有条件限制的转移,当条件不易表达时,尝试将无序选择转化为有序的顺次选择简化之。

为什么顺序插入身高是对的?假设我已经插入$i$个身高最矮的人,那么身高$i+1$的人除了插入每一行的末尾别无选择,试想如果插在排好的队中,显然不单调。和末尾空了一格或多格站,那么中间就找不到合适身高的人站进去了。当然也要保证插入的行的当前人数少于上一行的,不然上一行会比这一行少空位,之后身高更高的人也没办法站上去。这样做完,就可以保证排列方案满足要求。有没有什么方案不能通过上面这种方案构造出来的?没有,因为不按上面那种插入的话,其他情况必然无解。所以对于每一种可行方案,我可以认为他是按从小到大身高顺序每个依次在某一行末尾插入的得到的。那么我就可以顺理成章设f[a][b][c][d][e]来记录状态了,然后就是lyd书上的做法。对于每个状态,去推出其他可以拓展的后续状态(在这题也就是再插入身高排名下一位的人)。

实现上dp数组开满会爆内存,可以采用动态开数组(说白了就是主函数内部根据大小开数组),或者f[31][16][11][8][7]也可以,为什么您们都看得出来。。然而前者速度吊打后者,因为是动态开的嘛,后者每次还要全部清空。

其他一些细节(比如不满5行怎么办)看code,也可以照例解决,就把空的几行看成数组下标是0即可。

另:勾长公式挂在标题上是摆设。。我不太想学,因为有点冷门,而且应当不会考这玩意儿的说。。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define dbg(x) cerr<<#x<<" = "<<x<<endl
#define ddbg(x,y) cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl
using namespace std;
typedef long long ll;
template<typename T>inline char MIN(T&A,T B){return A>B?A=B,:;}
template<typename T>inline char MAX(T&A,T B){return A<B?A=B,:;}
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline T read(T&x){
x=;int p=;char c;while(!isdigit(c=getchar()))if(c=='-')p=;
while(isdigit(c))x=x*+(c&),c=getchar();return p?x=-x:x;
}
int x[];
int n;
int main(){//freopen("test.in","r",stdin);//freopen("test.out","w",stdout);
while(read(n),n){
memset(x,,sizeof x);
for(register int i=;i<=n;++i)read(x[i]);
unsigned int f[x[]+][x[]+][x[]+][x[]+][x[]+];
memset(f,,sizeof f);
f[][][][][]=;
for(register int a=;a<=x[];++a)
for(register int b=;b<=x[];++b)
for(register int c=;c<=x[];++c)
for(register int d=;d<=x[];++d)
for(register int e=;e<=x[];++e){
f[a+][b][c][d][e]+=f[a][b][c][d][e];
if(b<a)f[a][b+][c][d][e]+=f[a][b][c][d][e];
if(c<b)f[a][b][c+][d][e]+=f[a][b][c][d][e];
if(d<c)f[a][b][c][d+][e]+=f[a][b][c][d][e];
if(e<d)f[a][b][c][d][e+]+=f[a][b][c][d][e];
}
printf("%u\n",f[x[]][x[]][x[]][x[]][x[]]);
}
return ;
}

最新文章

  1. C语言_第五章__实践(密码转换)
  2. Nodejs学习路线图
  3. html 高亮显示表格当前行
  4. js数组去重的三种常用方法总结
  5. Orchard 候补神器说明
  6. [algorithm]求最长公共子序列问题
  7. Cisco中删除flash通过tftp服务器恢复
  8. present的时候是可以直接回到第一个viewcon的
  9. asp.net自动打卡、签到程序
  10. 背包类问题解答——poj3624分析
  11. QQ互联 redirect uri is illegal(100010)的解决办法,很简单
  12. Python-老男孩-02_装饰器_面向对象_封装_继承_异常_接口_数据库
  13. java的系统时间,怎么计算从现在到凌晨还剩下多少时间?
  14. openwrt 加入nand flash的支持
  15. avpicture_fill的实现
  16. ActiveQt框架 禁止弹出ActiveX控件交互提示
  17. python lxml库生成xml文件-节点命名空间问题
  18. Android之取消ViewPage+Fragment的预加载
  19. 使用CNN做数字识别和人脸识别
  20. ThinkPHP如果表名有下划线需要用Model应该怎么做?

热门文章

  1. GPL,BSD,Apache三个开源协定的大体联系及区别
  2. centos 6.5安装erlang和RabbitMQ
  3. TensorFlow实战第八课(卷积神经网络CNN)
  4. java 常用jar包方法
  5. 单例模式(一)static、final和单例模式
  6. BUUOJ misc 金三胖
  7. 在 sys.servers 中找不到服务器 &#39;10.0.2.13&#39;。请验证指定的服务器名称是否正确。
  8. JVM 线上故障排查基本操作 (转)
  9. 2019-2020Nowcoder Girl初赛题解
  10. Ansible PlayBook语法