「JXOI2017」加法
题目描述
可怜有一个长度为 n 的正整数序列 A ,但是她觉得 A 中的数字太小了,这让她很不开心。
于是她选择了 m 个区间 [li,ri] 和两个正整数 a , k 。她打算从这 m 个区间里选出恰好 k 个区间,并对每个区间执行一次区间加 a 的操作。
(每个区间最多只能选择一次。)
对区间 [l,r] 进行一次加 a 操作可以定义为对于所有 i∈[l,r] ,将 Ai 变成 Ai+a 。
现在可怜想要知道怎么选择区间才能让操作后的序列的最小值尽可能的大,即最大化 min 。
数据范围
\sum n \leq 2 \times 10^5,\sum m \leq 2 \times 10^5
题解
看到最小值最大化首先想到二分答案,然后贪心。
从 1 到 n 考虑每个 a_i 能否达到 mid 。如果没有达到的话,我们可以选择一些区间使它变大。
那我们应该选择怎样的区间呢?不难发现应该选择右端点更远的区间,这样对后面的 a 来说更容易达到 mid
所以我们可以把区间按照左端点排序,进行 two-pointer ,用堆维护右端点即可。
代码
#include <bits/stdc++.h> #define LL long long using namespace std; const int N=2e5+5; int T,n,m,k; LL f[N],in,a,s[N]; struct O{int l,r;}p[N]; bool cmp(O A,O B){return A.l<B.l;} bool J(LL x){ priority_queue<int>q; for (int i=1;i<=n;i++) s[i]=f[i]-f[i-1]; for (int j=1,r,i=1,l=0;i<=n;i++){ while(j<=m && p[j].l<=i) q.push(p[j++].r); s[i]+=s[i-1]; while(!q.empty() && s[i]<x && l<k){ r=q.top();q.pop(); if (r<i) break; s[i]+=a;l++;s[r+1]-=a; } if (s[i]<x) return 0; } return 1; } void work(){ scanf("%d%d%d%lld",&n,&m,&k,&a);in=2e18; for (int i=1;i<=n;i++) scanf("%lld",&f[i]),in=min(f[i],in); for (int i=1;i<=m;i++) scanf("%d%d",&p[i].l,&p[i].r); sort(p+1,p+m+1,cmp); LL l=in,r=in+a*k,mid; while(l<r){ mid=(l+r+1)>>1; if (J(mid)) l=mid; else r=mid-1; } printf("%lld\n",l); } int main(){ for (scanf("%d",&T);T--;work()); return 0; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥