POJ
来源:互联网 发布:一直正在准备windows 编辑:程序博客网 时间:2024/06/04 00:37
题目点此跳转
思路
题目意思是给你一个数组, 现在让你将整个数组划分为几个子区间,并且要保证每个子区间的元素和不大于M, 求 每个子区间的最大值 的和 的最小值。
这是一道dp题, 单调队列的一个很大的应用就是可以优化某一类dp。
我们先将它当作一个纯dp题去写状态转移方程,之后再考虑使用单调队列优化。
设 f(i) 为数组A[1, , i]满足条件的每个子区间的最大值的和 的最小值, 则要求的结果即为 f(n);
那么状态转移方程为:
f(j) = min(f(i) + max(A[k])), 0 < i < k < j;
可以这样理解 ,每增加一位元素,都要从这个元素出发向左扩展出一个区间,然后算这个区间里的最值加上它前面算好的f(i), 前提是这个区间的和也不能超过M。
如果直接枚举的话肯定也能出答案,但是会超时, 所以单调队列就派上用场了,我们的单调队列里可以保存对应区间范围内的最值,在每次向右滑动的时候更新这些最值,然后在dp的时候取出这些最值即可。
代码
(代码来自tsy)
int n, num[maxn], q[maxn];LL m, sum, f[maxn];int main() { scanf("%d%lld", &n, &m); int pos = 0, head = 0, tail = 0; for(int i = 1; i <= n; ++i) { scanf("%d", &num[i]); sum += num[i]; if(num[i] > m) { puts("-1"); return 0; } while(sum > m) sum -= num[++pos]; while(head<=tail && q[head] <= pos) ++head; while(head<=tail && num[q[tail]] <= num[i]) --tail; q[++tail] = i, f[i] = INF; for(int j = head, k = pos; j <= tail; k = q[j], ++j) { f[i] = min(f[i], f[k]+num[q[j]]); } } printf("%lld\n", f[n]); return 0;}
阅读全文
0 0
- POJ
- poj
- POJ
- POJ
- poj
- poj
- POJ
- POJ
- poj
- POJ
- POJ
- POJ
- POJ
- POJ
- POJ
- POJ
- POJ
- POJ
- 如何成为架构师系列:技术选型2
- oracle存储过程初学实例
- SElinux的开启和关闭
- 1980-分苹果
- vue-cli webpack config 配置详解
- POJ
- IBM要推POWER9,来了解一下POWER处理器的前世今生
- CNN架构模型的发展
- Unity特殊文件及脚本编译顺序(Special folders and script compilation order)
- 修改Oracle 的sqlplus 默认 的显示宽度和高度
- 记录springmvc中线程池的使用
- 在PDF Expert for Mac中你能填写的表单有多少
- js页脚点击展开折叠弹窗效果
- 英语词汇辨异 —— 同音字