题解 CF1355E Restorer Distance
[题目链接](Restorer Distance - 洛谷 | 计算机科学教育新生态 (luogu.com.cn))
发现,操作三(移动砖块)也可以转化为先拿一个砖块(操作二),再放一个砖块(操作一),那么当 时,当然尽可能使用操作三,但是当 时,使用操作三还不如先用操作二再用操作一,所以先对 做处理:,这样保证用操作三永远不劣。
如果知道最终所有砖块的高度,那么求解代价是简单的,通过猜测,发现函数是单谷函数(三分处理),最终结果确实如此,下面给出证明。
记 表示需要向上填补的砖块数, 表示需要向下削减的砖块数。 表示向上填的代价, 表示向下减的代价。 表示砖块总数, 表示最终砖块到达的高度, 表示所有砖块的初始高度, 表示总代价。
我们发现,对应不同情况,总代价有以下两种情况(注:式子经过恒等变形,需要进行一步推导):
容易发现,代价分成两端,不妨分开证明:
我们想要发现函数的增减性,不妨考虑相邻函数值的差值(即函数的增量)。
若 ,记 的增加量 ,记 的减小量 。注意:此时一定有 。
那么 (由于原来在高度及以下,现在高度加一,显然会导致这些需要向上增的加一),同理 。
那么原来贡献 变为 ,考虑 的增量,
不难发现,此处 是不增的(感性上直接理解为减即可),那么 就是增的。
所以我们证明了,在 时,随着 增加函数值 增。
同上可以证明,在这个区间内 减。
不妨思考一个问题:当 增加, 和 分别怎么变化。
当 特别小的时候, 肯定很小, 肯定很大,而当 慢慢增加, 会逐渐变大, 会逐渐变小,最终在 是时候发生转折,从 的情况过渡为 的情况。
所以整个函数一定是先降后增,即单谷函数。
但三分还需要满足一个条件,即:非极值点处不能出现平台。
出现平台则 。
那么由于当 是单调的(上文证明),例如对于 的情况来讲, 单调不降,也就是说,若 ,只有可能在极值点处取。所以便证明了 平台只有可能在极值点处取。
这样我们便证明了三分正确性。
总结:
- 证明函数增减考虑相邻差值;
- 对于分段函数证明,如果需要证明函数是单谷,则考虑证明两个分段函数增减性不同;
- 对于多变量,考虑找出变量与常量关系。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int N=1e5+10; int n,a,r,m; int h[N]; LL calc(int H) { LL s1=0,s2=0; //s1需要往上加,s2需要往下减 for(int i=1;i<=n;i++) { if(h[i]>H) s2+=h[i]-H; if(h[i]<H) s1+=H-h[i]; } if(s1>s2) return s2*m+(s1-s2)*a; else return (s2-s1)*r+s1*m; } int main(){ cin>>n>>a>>r>>m; m=min(m,a+r); int l=0,r=0; for(int i=1;i<=n;i++) { cin>>h[i]; r=max(r,h[i]); } while(r-l>=3) { int lmid=l+(r-l)/3,rmid=r-(r-l)/3; if(calc(rmid)>calc(lmid)) r=rmid; else l=lmid; } cout<<min({calc(l),calc(l+1),calc(l+2)}); return 0; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!