题面

  • 大意:一段长度为n的序列,分成若干段,每段值的总和不能超过m,求各段中最大值加起来的最小值。

其实最朴素的DP还是很好想的,以f[i]表示i及i以前已经分好所需的最小值,a[i]表示i点的值,那么枚举k,k满足

  1. k<i .
  2. \[(\sum^{j <= i }_{j = k+1}a[j] )<= m.
    \]

可用k更新f[i] : $$f[i]=\min(f[k]+\max(a[k+1->i]))$$

时间复杂度为O(n^2 ),明显T了。

那么一定是有很多的冗杂运算了,下面我们就来找出并避免这些运算。

  • 首先\(f[i]一定是单调不降的\),这很显然。

    那么我们可以找出来一些规律,当 \(\max(a[k+1->i])\) 固定时,\(k越小越好\),当\(\max(a[k+1->i])\)改变时,无法直接判断,仍是一种有可能成为最小值的情况,那么其他的k是没有用的,即 $$j1<j2,a[j1]<=a[j2]时,j2无用$$

    到这里已经可以看出来需要\(维护一个单调递减的单调队列\).

    但是单调队列中是a[k]递减,但\({f[k]+\max(a[k+1->i])}\)并不单调,需要用multiset来维护一下,其中\(\max(a[k+1->i])\)其实就是队列中的下一个元素的值,insert(f[k]+a[k的下一个元素])即可,队列与set同时insert和pop(这里的细节较多,后面看代码注释),因为每个k最多入队和出队一次,单调队列均摊O(1),set维护log(N),总时间复杂度O(Nlog(N)).

    看代码:注意数据范围,得开long long。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int,int> pii;
#define mk make_pair
#define ps push_back
#define fi first
#define se second
inline int read(){
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9')f=c=='-'?-1:1,c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
return f*x;
}
const int N=1e5+10,inf=0x7fffffff;
long long n,m,f[N],a[N];
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
n=read(),m=read();
ll x=0,k=1,tp=0;
for(int i=1;i<=n;++i){
a[i]=read();if(a[i]>m)return puts("-1"),0;//不可能情况
}
multiset<ll> s;
deque<ll> q;
for(int i=1;i<=n;++i){
x+=a[i];
while(x>m)x-=a[k++];//保证sum(a[k->i])<=m
while(!q.empty()&&q.front()<k){//在k之前的点不要,pop掉
tp=f[q.front()];q.pop_front();
if(!q.empty())s.erase(tp+a[q.front()]);//当!q.empty()时,说明set里已经放入了\
(a[q.front()]+f[q.front()的上一个元素]),需要pop(tp+a[q.front()]),下面一样。
}
while(!q.empty()&&a[q.back()]<=a[i]){//保证队列单调递减
tp=a[q.back()];q.pop_back();
if(!q.empty())s.erase(tp+f[q.back()]);
}
if(!q.empty())s.insert(f[q.back()]+a[i]);//队列中每两个相邻元素就得insert一次
q.push_back(i);
f[i]=f[k-1]+a[q.front()];//选择了k->i整个区间,\
因为该段区间最大值(a[q.front()])与f[k-1]也构成一对可能解。
if(s.size())f[i]=min(f[i],*s.begin());//注意判空
}
printf("%lld\n",f[n]);
return 0;
}

Cut the Sequence(单调队列DP+set)的更多相关文章

  1. $Poj3017\ Cut\ The\ Sequence$ 单调队列优化$DP$

    Poj   AcWing Description 给定一个长度为N的序列 A,要求把该序列分成若干段,在满足“每段中所有数的和”不超过M的前提下,让“每段中所有数的最大值”之和最小. N<=10 ...

  2. poj3017 Cut the Sequence 单调队列 + 堆 dp

    描述 把一个正数列 $A$分成若干段, 每段之和 不超过 $M$, 并且使得每段数列的最大值的和最小, 求出这个最小值. 题目链接 题解 首先我们可以列出一个$O(n^2)$ 的转移方程 : $F_i ...

  3. POJ 3017 单调队列dp

    Cut the Sequence Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8764   Accepted: 2576 ...

  4. [TyvjP1313] [NOIP2010初赛]烽火传递(单调队列 + DP)

    传送门 就是个单调队列+DP嘛. ——代码 #include <cstdio> ; , t = , ans = ~( << ); int q[MAXN], a[MAXN], f ...

  5. zstu 4237 马里奥的求救——(单调队列DP)

    题目链接:http://oj.acm.zstu.edu.cn/JudgeOnline/problem.php?id=4237 这题可以转化为每次可以走g~d+x步,求最大分数,且最大分数的步数最少. ...

  6. 1304F2 - Animal Observation (hard version) 线段树or单调队列 +DP

    1304F2 - Animal Observation (hard version) 线段树or单调队列 +DP 题意 用摄像机观察动物,有两个摄像机,一个可以放在奇数天,一个可以放在偶数天.摄像机在 ...

  7. Cow Hopscotch (单调队列 + DP)

    链接:https://ac.nowcoder.com/acm/contest/1113/K来源:牛客网 The cows have reverted to their childhood and ar ...

  8. vijos P1243 生产产品(单调队列+DP)

      P1243生产产品   描述 在经过一段时间的经营后,dd_engi的OI商店不满足于从别的供货商那里购买产 品放上货架,而要开始自己生产产品了!产品的生产需要M个步骤,每一个步骤都可以在N台机器 ...

  9. POJ 1821 单调队列+dp

    题目大意:有K个工人,有n个墙,现在要给墙涂色.然后每个工人坐在Si上,他能刷的最大范围是Li,且必须是一个连续子区间,而且必须过Si,他刷完后能获得Pi钱 思路:定义dp[i][j]表示前i个人,涂 ...

  10. codeforces 1077F2. Pictures with Kittens (hard version)单调队列+dp

    被队友催着上(xun)分(lian),div3挑战一场蓝,大号给基佬紫了,结果从D开始他开始疯狂教我做人??表演如何AKdiv3???? 比赛场上:A 2 分钟,B题蜜汁乱计数,结果想得绕进去了20多 ...

随机推荐

  1. 【Spring-Security】Re09 CSFR处理

    一.CSRF: CSRF 全称 Cross Site Request Forgery 跨站请求伪造 又称为OneClick Attack & SessionRiding 是非法请求访问,通过伪 ...

  2. iOS开发基础148-ABM vs MDM

    Apple Business Manager (ABM) vs. Mobile Device Management (MDM) Apple Business Manager (ABM) 优点: 集中管 ...

  3. net8实现MediatR小示例C#

    MediatR是.net下的一个实现消息传递的库,简洁高效,它采用中介者设计模式,通过进程内消息传递机制,进行请求/响应.命令.查询.通知和事件的消息传递,可通过泛型来支持消息的智能调度,用于领域事件 ...

  4. C语言操作时间函数time.ctime,实现定时执行某个任务小例子

    时间操作函数在实际项目开发中会经常用到,最近做项目也正好用到就正好顺便整理一下. 时间概述 由上图可知: 通过系统调用函数time()可以从内核获得一个类型为time_t的1个值,该值叫calenda ...

  5. 5. 从0开始学ARM-MRS、MSR、寻址操作、原子操作原理

    一.程序状态寄存器访问指令 ARM微处理器支持程序状态寄存器访问指令,用于在程序状态寄存器和通用寄存器之间传送数据. MRS MRS{条件} 通用寄存器,程序状态寄存器(CPSR或SPSR) MRS指 ...

  6. 11. 基于ARM Cortex-A9中断详解

    一.中断概念 操作系统中,中断是很重要的组成部分.出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行. 有了中断系统才可以不用一直 ...

  7. Win32 自绘控件按钮类

    今天学了控件的自绘,初步偿试了下,蹂躏的不行不行的,查了好多的资料,头都弄大了, 有好多还是没弄明白,只是初步实现一个按钮的基本功能,好难呀, 先看下效果: 按下状态 弹起状态 按钮2按下状态 按钮2 ...

  8. apr库编译及队列使用笔记

    操作系统 :CentOS 7.9_x64 apr库版本:apr-1.7.4 & apr-util-1.6.3 gcc 版本:4.8.5 队列功能在C++或Python等脚本语言里面,是很容易就 ...

  9. 【YashanDB知识库】绑定参数,同一个sql多个执行计划的问题

    问题现象 同一个sql有两个执行计划,是否合理? 它的EXECUTIONS,ELAPSED_TIME等统计信息怎么看,是独立分开的还是统一计算的? 如下图: 问题影响版本 tpcc测试:23.2.1. ...

  10. Linux IP 命令

    改MAC 地址 ip link set dev nic1 downip link set dev nic1 address 0c:42:a1:8f:a4:47ip link set dev nic1 ...