CF1852C Ina of the Mountain

*2400 https://codeforces.com/problemset/problem/1852/C

如果没有 modk 的限制的话,我们都会做,因为都是正数,那么 indi>0,因此,答案即为 [di>0]di

但是现在多了一个操作,即为区间加 k,那么转到差分数组就是 dl+k,drk,且该操作不花费。

观察,差分数组的值域范围为 [1k,k1]

那么,你现在要多用这个操作,使得 [di>0]dimin

考虑扫过去,若 di0,那么显然是不在和式里的,但是,它可以执行新操作,为后面提供 k 的机会。但是新操作会用多少次呢?显然至多一次,因为如果 dl>0,那么我们对 dl+k 是没意义的。因为这样多了 k 的贡献,但是后面至多减少 k 的贡献,那么这样肯定是不优的。我常常将这种区间操作然后提供机会的东西抽象成流量,也就是说,当前会提供 1 的流量。

di>0,那么它显然只能消耗流量。如果没有流量给他消耗了,那么直接贡献到和式当中。如果有流量,仿照费用流的贪心,如果流过之后,和式更大,那么显然不流更优。同样的,仿照网络流问题,对于一个流量的消耗,我们总需要建立反向边,让他有机会退流,得到反悔的效果。那么,在这里,这个反向边实际上的作用就是再提供一个流量。

那么,对贡献写一下柿子即可,若 di>0,选了一个 dj<0 流量,那么贡献要么流 dj+m,要么不流,di,注意类添加反向边即可。

#include <bits/stdc++.h> #define int long long #define pb push_back using namespace std; const int N=(int)(2e5+5); multiset<int>s; int n,a[N],m,d[N]; void sol() { s.clear(); cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) if(a[i]==m) a[i]=0; for(int i=1;i<=n;i++) d[i]=a[i]-a[i-1]; int ans=0; for(int i=1;i<=n;i++) { if(d[i]==0) continue ; // cout<<d[i]<<": "; // if(!s.empty()) cout<<*s.begin(); // cout<<'\n'; if(d[i]<0) { s.insert(d[i]); } else { if(s.empty()) { ans+=d[i]; continue ; } int mi=*s.begin(); if(mi+m<=d[i]) ans+=mi+m,s.erase(s.begin()),s.insert(d[i]-m); else ans+=d[i]; } } cout<<ans<<'\n'; } signed main() { cin.tie(0); ios::sync_with_stdio(false); int T; cin>>T; while(T--) sol(); return 0; }

__EOF__

本文作者F x o r G
本文链接https://www.cnblogs.com/xugangfan/p/17683254.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   FxorG  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示