[UVA12235] Help Bubu 思维题+状态定义+Dp
Online Judge:UVA12235
Label:思维题,状态定义,状压Dp
题面:
题目描述
有一个书架,上面放了n本书,从左往右的第i本书的高度为h[i]。定义书架的混乱度为连续等高段的个数。
例如:{30,30,31,31,32}的混乱度为3;{30,32,32,31}的混乱度为3;{31,32,31,32,31}的混乱度为5。
现在你可以从中抽出至多k本书,然后将他们随意放回书架任意位置,求最终最小的混乱度。
对于100%的数据,N的范围[1,500],K的范围[1,100],书的高度范围[25,32];
输入
第一行两个整数N,K;
第二行,N个元素,表示从左往右每本书的高度。
输出
输出重新摆放K本书的最小混乱度。
"Print a blank line after the output of each case."注意每组数据输出要两个换行!!
样例
Input
5 2
25 25 32 32 25
5 1
25 26 25 26 25
0 0
Output
Case 1: 2
Case 2: 3
题解
发现书的高度只有\([25,32]\)这8种,似乎可以状压的样子。对高度重新编号\(0\)~\(7\)方便后面表示,并且称为\(8\)种不同的颜色。
定义状态\(dp[i][j][sta][co]\),只考虑前\(i\)本书,已经将其中\(j\)本书拿起来了(注意这里是拿起来,其实是采用一种上帝视角,先全部拿出来然后到时候一个一个再放回去),\(sta\)表示哪些颜色的书还没拿起来过(用二进制表示状态),\(co\)表示最近一次没拿起来的书的颜色,Dp值表示此时(i及其之前)剩下来没有移动的那些书的混乱度。
然而你会发现直接这样定数组会MLE,如何优化呢,只要你把题解拉下来一点直接看转移过程,就会发现,对于第一维来说每次只用上一层状态,所以可以滚动一下第一维。这样空间就没问题勒。
先来讲讲接下来具体如何实现:
初态:对于任意\(h∈[h[1],h[n]]\) 有 \(dp[i][i-1][1<<h][h]\)表示,除了当前这本书,前面的\(i-1\)本书都拿起来时的状态;
终态:统计\(dp[n][j][sta][co]+val\)的最小值,其中\(val\)=\(all\) \(Xor\) \(sta\)中1的个数,其实就是那些拿起来的书的颜色种类总数。
而转移呢可以一边读入一边进行。对于当前的高度\(h\)(先-24转化成0~7中的数字),我们枚举\(i,sta,co\),详见下面注释:
inline void Do(int &x,int y){if(x==-1||x>y)x=y;}
//枚举第o本书
int g=0,all=0;
Rep(o,1,n){
//读入高度,预处理下
int h;scanf("%d",&h);h-=25;
//滚动~
g^=1;memset(dp[g],-1,sizeof(dp[g]));
//上面所说的初态初始化。注意要判:o-1<=m,因为第二维我们只开到m的上限100,不特判可能会数组越界
if(o-1<=m)dp[g][o-1][1<<h][h]=1;
//i:已拿个数 s:未选颜色状态 c:最近一次没动的书的颜色
Rep(i,0,min(o,m))Rep(s,1,all)Rep(c,0,7){//枚举上一层状态
if(dp[g^1][i][s][c]==-1)continue;
//最近的位置上有一个跟h颜色相同的书没拿走,很明显把当前这个留下来较优
if(h==c)Do(dp[g][i][s][c],dp[g^1][i][s][c]);
else{
//把当前这个留在原位,由于前面一个跟自己颜色不同,所以混乱值+1
Do(dp[g][i][s|(1<<h)][h],dp[g^1][i][s][c]+1);
//把当前这个拿起来
Do(dp[g][i+1][s][c],dp[g^1][i][s][c]);
}
}
all|=1<<h;//all表示当前已经含有的颜色
}
最后的统计根据上面的终态来就好了。
上完整代码:
#include<bits/stdc++.h>
#define Rep(a,b,c) for(int a=b;a<=c;++a)
using namespace std;
int n,m,dp[2][115][260][10];
inline void Do(int &x,int y){
if(x==-1||x>y)x=y;
}
int main(){
int cas=0;
while(~scanf("%d%d",&n,&m)){
if(n==0||m==0)return 0;memset(dp,-1,sizeof(dp));
int g=0,all=0;
Rep(o,1,n){
int h;scanf("%d",&h);h-=25;
g^=1;memset(dp[g],-1,sizeof(dp[g]));
if(o-1<=m)dp[g][o-1][1<<h][h]=1;
Rep(i,0,min(o,m))Rep(s,1,all)Rep(c,0,7){
if(dp[g^1][i][s][c]==-1)continue;
if(h==c)Do(dp[g][i][s][c],dp[g^1][i][s][c]);
else{
Do(dp[g][i][s|(1<<h)][h],dp[g^1][i][s][c]+1);
Do(dp[g][i+1][s][c],dp[g^1][i][s][c]);
}
}
all|=1<<h;
}
int ans=n;
Rep(i,0,m)Rep(s,1,all)Rep(c,0,7)if(~dp[g][i][s][c]){
int cnt=0,choose=all^s;
Rep(o,0,7)if((1<<o)&choose)cnt++;
ans=min(ans,dp[g][i][s][c]+cnt);
}
printf("Case %d: %d\n\n",++cas,ans);
}
}
End
重新看一遍这道题,难点主要在于正确定义状态。状压、滚动这两个优化根据数据范围和转移过程并不难想。为什么可以以这样的顺序从前到后遍历转移呢,考试的时候也有思考过这样的顺序,但是马上能找到反例——可能前面的书也可以放在他之后的块里。实际上还是没有想通那个上帝视角,即将这些拿出来的书先囤着,到时候一个一个贪心的插♂回去,不急着确定出到底要放在哪个块里。
[UVA12235] Help Bubu 思维题+状态定义+Dp的更多相关文章
- 思维题练习专场-DP篇(附题表)
转载请注明原文地址http://www.cnblogs.com/LadyLex/p/8536399.html 听说今年省选很可怕?刷题刷题刷题 省选已经结束了但是我们要继续刷题刷题刷题 目标是“有思维 ...
- Educational Codeforces Round 59 (Rated for Div. 2) E 区间dp + 状态定义 + dp预处理(分步dp)
https://codeforces.com/contest/1107/problem/E 题意 给出01字符串s(n<=100),相邻且相同的字符可以同时消去,一次性消去i个字符的分数是\(a ...
- 【思维题 状压dp】APC001F - XOR Tree
可能算是道中规中矩的套路题吧…… Time limit : 2sec / Memory limit : 256MB Problem Statement You are given a tree wit ...
- hdu 5119 (类似于划分数的状态定义) (DP中的计数问题)
题目描述:求n个数中异或值大于m的方案数有多少个? 设状态f[i][j]代表前i个数异或值为j的方案数有f[i][j]种,那么对于j来说要么选第i个数与前面的i-1个数中的某些数构成j,f[i-1][ ...
- [Hdu-5155] Harry And Magic Box[思维题+容斥,计数Dp]
Online Judge:Hdu5155 Label:思维题+容斥,计数Dp 题面: 题目描述 给定一个大小为\(N*M\)的神奇盒子,里面每行每列都至少有一个钻石,问可行的排列方案数.由于答案较大, ...
- [SHOI2007] 书柜的尺寸 思维题+Dp+空间优化
Online Judge:Luogu-P2160 Label:思维题,Dp,空间优化 题面: 题目描述 给\(N\)本书,每本书有高度\(Hi\),厚度\(Ti\).要摆在一个三层的书架上. 书架的宽 ...
- BZOJ 2734 洛谷 3226 [HNOI2012]集合选数【状压DP】【思维题】
[题解] 思维题,看了别人的博客才会写. 写出这样的矩阵: 1,3,9,... 2,6,18,... 4,12.36,... 8,24,72,... 我们要做的就是从矩阵中选出一些数字,但是不能选相邻 ...
- hdu6006 Engineer Assignment 状态dp 定义dp[i][s]表示前i个工程状态为s可以执行的最大工程数。s表示前i个工人选走了s状态的工程师。
/** 题目:hdu6006 Engineer Assignment 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6006 题意:已知n个工程,每个需要某 ...
- 状态压缩dp增量统计贡献——cf1238E(好题)
这题的状态设计非常巧妙,因为dp[S]表示的并非当前正确的值,而是维护一个中间量,这个中间量在到达末状态时才正确 当然官方的题解其实更加直观,只不过理解起来其实有点困难 /* 给定一个串s,字符集为2 ...
随机推荐
- LeetCode第三题—— Longest Substring Without Repeating Characters(最长无重复子字符串)
题目描述 Given a string, find the length of the longest substring without repeating characters. Example ...
- lock tables和unlock tables
1.lock tables table1 read,table2 read,table3 read igoodful@a8-apple-iphone-db00.wh(glc) > show ta ...
- day21 生成器,列表解析,三元表达式
Python之路,Day9 = Python基础9 判断可迭代对象和迭代器 from collections import Iterable, Iterator # 导入模块功能,用来判断对象是否为I ...
- 线段树+欧拉函数——cf1114F
调了半天,写线段树老是写炸 /* 两个操作 1.区间乘法 2.区间乘积询问欧拉函数 欧拉函数计算公式 phi(mul(ai))=mul(ai) * (p1-1)/p1 * (p2-1)/p2 * .. ...
- C/C++语言实现单链表(带头结点)
彻底理解链表中为何使用二级指针或者一级指针的引用 数据结构之链表-链表实现及常用操作(C++篇) C语言实现单链表,主要功能为空链表创建,链表初始化(头插法),链表元素读取,按位置插入,(有序链表)按 ...
- BZOJ 1398: Vijos1382寻找主人 Necklace(最小表示法)
传送门 解题思路 最小表示法.首先对于判断是不是循环同构的串,直接扫一遍用哈希判即可.然后要输出字典序最小的就要用到最小表示法,首先可以把串复制一遍,这样的话就可以把串变成静态操作.如果对于两个位置\ ...
- 几个dp的陈年老题
真 陈年老题 都是基础的dp优化 主要是展现我基础薄弱,菜得抠脚 1.四边形不等式 四边形不等式:w[i][j]+w[i+1][j+1]<=w[i+1][j]+w[i][j+1] 对于f[i][ ...
- net.sf.jsqlparser.statement.select.PlainSelect.getGroupBy()Lnet/sf/jsqlparse
添加pom依赖 <dependency> <groupId>com.github.jsqlparser</groupId> <artifactId>js ...
- 转: sizeof,总结
源地址:http://blog.csdn.net/freefalcon/article/details/54839 0. 前向声明 sizeof,一个其貌不扬的家伙,引无数菜鸟竟折腰,小虾我当初也没少 ...
- 【LGP5349】幂
题目 比较厉害的题目了 求 \[\sum_{i=0}^{\infty}\sum_{j=0}^nf_ji^jr^i\] 改变一下求和顺序 \[\sum_{j=0}f_j\sum_{i=0}^{\inft ...