正题

题目链接:https://www.ybtoj.com.cn/problem/463


题目大意

给出长度为\(n\)的序列\(A,B\)。要求划分成若干段满足

  1. 对于任何\(i<j\),若\(i\)和\(j\)不是同一段的,要求满足\(B_i>A_j\)
  2. 每一段\(A_i\)的最大值的和不能超过\(m\)

要求最小化每一段\(B_i\)和的最大值。

\(n\in[1,10^5],A_i,B_i\in[1,10^9],m\in[1,10^{12}]\)


解题思路

最大值最小化很显然直接二分,然后变为求每一段\(A_i\)最大值的和的最小值。

第一个条件相当于限制了什么位置能够作为划分段的末尾,求一个前缀\(min\{b_i\}\)和一个后缀\(max\{a_i\}\)能够快速求出这些位置。

然后考虑\(dp\),转移方程就是

\[f_i=min\{f_j+max\{a_k\}(\ k\in(j,i]\ )\}
\]

二分的条件限制了\(j\)的范围,加个指针就好了

这个东西好像很难搞,但是注意到\(v_j=max\{a_k\}\)这一部分是递减的,并且每次会让所有\(v_i\)的一起和一个一起取\(max\)。

因为是递减的,所以每次加入一个新的就相当于修改一段后缀的\(v_i\),然后求一个区间的最大\(f_i+v_i\)了。

可以线段树维护,每个节点维护该区间最大的\(f_i+v_i\)和最大的\(f_i\)。区间推平\(v_i\)的时候就可以拿最大的\(f_i\)来更新\(f_i+v_i\)

时间复杂度\(O(n\log n\log\sum b_i)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1e5+10,inf=1e9+7;
ll n,m,a[N],b[N],pre[N],suf[N],last[N];
ll lg[N],st[N][17],v[N<<2],w[N<<2],lazy[N<<2];
void Downdata(ll x){
if(!lazy[x])return;
lazy[x*2]=lazy[x*2+1]=lazy[x];
w[x*2]=v[x*2]+lazy[x];
w[x*2+1]=v[x*2+1]+lazy[x];
lazy[x]=0;return;
}
void Changew(ll x,ll L,ll R,ll l,ll r,ll val){
if(l>r)return;
if(L==l&&R==r){w[x]=v[x]+val;lazy[x]=val;return;}
ll mid=(L+R)>>1;Downdata(x);
if(r<=mid)Changew(x*2,L,mid,l,r,val);
else if(l>mid)Changew(x*2+1,mid+1,R,l,r,val);
else Changew(x*2,L,mid,l,mid,val),Changew(x*2+1,mid+1,R,mid+1,r,val);
w[x]=min(w[x*2],w[x*2+1]);
}
void Changev(ll x,ll l,ll r,ll pos,ll val){
if(l==r){v[x]=val;w[x]=v[x]+lazy[x];return;}
ll mid=(l+r)>>1;Downdata(x);
if(pos<=mid)Changev(x*2,l,mid,pos,val);
else Changev(x*2+1,mid+1,r,pos,val);
w[x]=min(w[x*2],w[x*2+1]);
v[x]=min(v[x*2],v[x*2+1]);
return;
}
ll Ask(ll x,ll L,ll R,ll l,ll r){
if(L==l&&R==r)return w[x];
ll mid=(L+R)>>1;Downdata(x);
if(r<=mid)return Ask(x*2,L,mid,l,r);
if(l>mid)return Ask(x*2+1,mid+1,R,l,r);
return min(Ask(x*2,L,mid,l,mid),Ask(x*2+1,mid+1,R,mid+1,r));
}
ll RMQ(ll l,ll r){
ll z=lg[r-l+1];
return max(st[l][z],st[r-(1<<z)+1][z]);
}
bool check(ll x){
memset(v,0x3f,sizeof(v));
memset(w,0x3f,sizeof(w));
memset(lazy,0,sizeof(lazy));
ll sum=0,l=0,tmp=v[0];
Changev(1,0,n,0,0);
for(ll i=1;i<=n;i++){
sum+=b[i];
while(sum>x)l++,sum-=b[l];
Changew(1,0,n,last[i],i-1,a[i]);
if(pre[i]<=suf[i+1])continue;
tmp=Ask(1,0,n,l,i);
Changev(1,0,n,i,tmp);
}
return (tmp<=m);
}
signed main()
{
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
scanf("%lld%lld",&n,&m);
ll l=1,r=0;pre[0]=inf;
for(ll i=1;i<=n;i++)
scanf("%lld%lld",&a[i],&b[i]),r+=b[i],l=max(l,b[i]),st[i][0]=a[i];
for(ll i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
for(ll j=1;(1<<j)<=n;j++)
for(ll i=1;i+(1<<j)-1<=n;i++)
st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);
for(ll i=1;i<=n;i++){
ll l=1,r=i-1;
while(l<=r){
ll mid=(l+r)>>1;
if(RMQ(mid,i)>a[i])l=mid+1;
else r=mid-1;
}
last[i]=r;
}
for(ll i=1;i<=n;i++)
pre[i]=min(pre[i-1],b[i]);
for(ll i=n;i>=1;i--)
suf[i]=max(suf[i+1],a[i]);
while(l<=r){
ll mid=(l+r)>>1;
if(check(mid))r=mid-1;
else l=mid+1;
}
check(l+1);
printf("%lld\n",l);
}

YbtOJ#463-序列划分【二分答案,线段树,dp】的更多相关文章

  1. [BZOJ4552][TJOI2016&&HEOI2016]排序(二分答案+线段树/线段树分裂与合并)

    解法一:二分答案+线段树 首先我们知道,对于一个01序列排序,用线段树维护的话可以做到单次排序复杂度仅为log级别. 这道题只有一个询问,所以离线没有意义,而一个询问让我们很自然的想到二分答案.先二分 ...

  2. bzoj 4552 [Tjoi2016&Heoi2016]排序 (二分答案 线段树)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4552 题意: 给你一个1-n的全排列,m次操作,操作由两种:1.将[l,r]升序排序,2 ...

  3. BZOJ 4552 [Tjoi2016&Heoi2016]排序 | 二分答案 线段树

    题目链接 题面 题目描述 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这 ...

  4. HDU 5649 DZY Loves Sorting(二分答案+线段树/线段树合并+线段树分割)

    题意 一个 \(1\) 到 \(n\) 的全排列,\(m\) 种操作,每次将一段区间 \([l,r]\) 按升序或降序排列,求 \(m\) 次操作后的第 \(k\) 位. \(1 \leq n \le ...

  5. 【BZOJ4552】【HEOI2016】排序 [二分答案][线段树]

    排序 Time Limit: 60 Sec  Memory Limit: 256 MB[Submit][Status][Discuss] Description 在2016年,佳媛姐姐喜欢上了数字序列 ...

  6. 【Luogu】P2824排序(二分答案+线段树排序)

    题目链接 震惊!两个线段树和一个线段树竟是50分的差距! 本题可以使用二分答案,二分那个位置上最后是什么数.怎么验证呢? 把原序列改变,大于等于mid的全部变成1,小于mid的全部变成0,之后线段树排 ...

  7. [HEOI2016/TJOI2016] 排序 解题报告(二分答案/线段树分裂合并+set)

    题目链接: https://www.luogu.org/problemnew/show/P2824 题目描述: 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在 ...

  8. [BZOJ4552][Tjoi2016&Heoi2016]排序(二分答案+线段树)

    二分答案mid,将>=mid的设为1,<mid的设为0,这样排序就变成了区间修改的操作,维护一下区间和即可 然后询问第q个位置的值,为1说明>=mid,以上 时间复杂度O(nlog2 ...

  9. 洛谷P3246 序列 [HNOI2016] 莫队/线段树+扫描线

    正解:莫队/线段树+扫描线 解题报告: 传送门! 似乎是有两种方法的,,,所以分别港下好了QAQ 第一种,莫队 看到这种询问很多区间之类的就会自然而然地想到莫队趴?然后仔细思考一下,发现复杂度似乎是欧 ...

随机推荐

  1. C# 排序列表(SortedList)

    SortedList 类代表了一系列按照键来排序的键/值对,这些键值对可以通过键和索引来访问. 排序列表是数组和哈希表的组合.它包含一个可使用键或索引访问各项的列表.如果您使用索引访问各项,则它是一个 ...

  2. 刷题-力扣-541. 反转字符串 II

    541. 反转字符串 II 题目链接 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/reverse-string-ii 著作权归领扣网络所有. ...

  3. dpkg:处理 xxx (--configure)时出错解决办法,也可用于卸载软件出错的情况

    dpkg:处理 xxx (--configure)时出错解决办法今早安装nfs时出现问题,找到该文,备份留用.然后在网上找到了这片文章,按步骤走就解决了,中间会提示自动卸载一下,执行那个命令就好了,我 ...

  4. os.read

    #-*-coding:utf-8-*-__author__ = "logan.xu"import oscmd_res=os.popen("ls").read() ...

  5. Java 登录模块设计

    登录流程 前端登录传输用户名和md5加密后的密码 后端对密码在进行md5加密,或者使用md5加密的密码 + id 进行盐加密,增加密码被破解的难度. 登录成功后,这里分成单体,或者分布式的情况 单体 ...

  6. Linux下SSH以及SSH秘钥

    一.基于秘钥方式实现远程连接 第一步:创建密钥对(在管理端服务器上操作) 中间的输入项可以直接回车 ssh-keygen -t dsa 第二步:分发公钥(在管理端服务器执行) 这个步骤需要输入一个ye ...

  7. MySQL——MySQL安装

    1.rpm yum安装:安装方便.速度快.无法定制 2.二进制安装:解压即可使用,不能定制功能 3.编译安装: 可定制.安装慢: MySQL5.5之前:./configure make make in ...

  8. noip模拟39

    \(\color{white}{\mathbb{百般红紫博众爱,正是芳菲斗艳时,名之以:牡丹}}\) %%% szs巨佬AK \(t1\).\(t4\) 都会做,剩下两道好像都不太会,再次扫描到知识盲 ...

  9. 区间DP的瞎扯淡

    写在前面连个引言都不加就直接开1. 区间DP状态常见模板: f[i][j]常常表示第i个到第j个这个区间内达到题目要求,所需要的最小值(最大值) 如: 1. [石子合并](https://www.lu ...

  10. TCP可靠传输原理

    停止等待协议 "停止等待"就是发送方在发送完一个分组后停止发送,等待接收方的确认后再继续发送. 超时重传 发送方在等待一定时间后如果还没有收到接收方的确认,此时发送方将认定分组没有 ...