description
你要挖井,个地面的高度可视为,每次操作你可以将一个,你最多可执行次操作。
你要任选其中一个挖到,问你相邻的高度差的最大值最小。并输出满足其的最小的井。
solution
二分最大值。
先不考虑挖井到0。用最少的步数,把削到满足条件。
削我一开始想到是用堆,每次最小的那个肯定不会被削,削它两边的。
其实直接从左往右,削左小右大的;再从右往左削左大右小的。
证明?第一遍后不存在,第二遍会保持第一遍的性质(对于第一遍被削的,显示如果被削且差大于了,当且仅当他们大小颠倒变为左大右小,然后下一步会把削合法),且满足。得证。
从左往右枚举每个当井。从->必然,会牵涉到两边,即一个区间降低。
具体的,两边在斜率为,过该店的直线上方的点会被削到刚好在直线上。
只要有一个本身在直线下的点,之后都会在直线下,因此是一个区间。
随着井->,区间相当于双指针,都会往右移。
证明?对于左边部分的直线变高,在直线下的更多,缩范围;同理而右边直线会变低,直线下的更少,阔范围。
总结:二分+削减+枚举井(维护双指针)
code:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
int n,h[N],a[N],up;
ll s[N],m;
ll calc(int t,ll ch) {
if(!t)return 0;
return (ch*t+ch)*t/2;
}
int check(ll mid) {
// printf("%d:~~~~~~\n",mid);
for(int i=1;i<=n;i++)h[i]=a[i];
ll pay=0;
for(int i=2;i<=n;i++) if(h[i]-h[i-1]>mid){pay+=h[i]-h[i-1]-mid;h[i]=h[i-1]+mid;}//左小右大
for(int i=n-1;i;i--) if(h[i]-h[i+1]>mid){pay+=h[i]-h[i+1]-mid;h[i]=h[i+1]+mid;} //左大右小
// printf("pay = %lld\n",pay);
if(pay>m)return 0;
for(int i=1;i<=n;i++) s[i]=s[i-1]+h[i];
int l=1,r=1;
for(int i=1;i<=n;i++) { //井
while(l<i&&h[l]<(i-l)*mid) {l++;} //l满足
while(r<n&&h[r+1]>=(r+1-i)*mid) {r++;} //r不满足
ll cost=pay+s[r]-s[l-1]-(calc(i-l,mid)+calc(r-i,mid));
if(cost<=m) {return i;}
}
return 0;
}
void solve() {
int l=0,r=up,f,id;
while(l<=r) {
int mid=(l+r)>>1,p=check(mid);
if(p) {f=mid;id=p;r=mid-1;}
else {l=mid+1;}
}
printf("%d %d",id,f);
}
int main() {
// freopen("data.in","r",stdin);
scanf("%d%lld",&n,&m);
for(int i=1;i<=n;i++) {scanf("%d",&h[i]);a[i]=h[i];up=max(up,h[i]);}
solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人