Gym - 100851L:Landscape Improved (二分+单调性)
2024-09-01 01:58:08
题意: 一个宽度为N的网格图,i上有h[i]高的方块。现在你有W个方块,问怎么放使得最终的最高点最高。
当一个格子的下方,左下方和右下方都有方块那么久可以把方块放到这个格子上。最左端和最右端不能放方块。
(N<=100000,W<=1018,h[i]<=109)
思路:显然是二分,对于二分的高度Mid,我们验证是否有i能够达到这个高度。我们已知需要填充的部分是从i向两旁延伸,知道左边满足i-pos>=Mid-h[pos]
右边满足pos-i>=Mid-h[pos],我们需要对于每个i找到Lpos和Rpos,然后用前缀和O(1)算出需要的方块。
现在的关键就是对于Mid,O(N)内预处理得到L和R数组:对于pos,它影响的范围是pos+Mid-h[pos]及其以后,那么记录下L[pos+Mid-h[pos]]=pos,然后扫描更新一遍最大值即可;R数组同理。
(emmm,我个zz,果然还是太弱。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=;
int N,L[maxn],R[maxn]; ll sum[maxn],h[maxn],W;
bool check(ll Mid)
{
int i; for(i=;i<=N+;i++) L[i]=,R[i]=N+;
for(i=;i<=N;i++) if(i+Mid-h[i]<=N&&i+Mid-h[i]>=i) L[i+Mid-h[i]]=i;
for(i=N;i>=;i--) if(i-Mid+h[i]>=&&i-Mid+h[i]<=i) R[i-Mid+h[i]]=i; //方向不能反,因为要最近的
for(i=;i<=N;i++) L[i]=max(L[i],L[i-]);
for(i=N;i>=;i--) R[i]=min(R[i],R[i+]);
for(i=;i<=N;i++){
if(R[i]==N+||L[i]==) continue;
ll res=;
res+=1LL*(Mid+Mid-(i-L[i])+)*(i-L[i])/;
res+=1LL*(Mid-+Mid--(R[i]-i-)+)*(R[i]-i-)/;
res-=sum[R[i]-]-sum[L[i]];
if(res<=W) return true;
}
return false;
}
int main()
{
scanf("%d%I64d",&N,&W);
ll l=,r=,Mid,ans;
for(int i=;i<=N;i++) scanf("%I64d",&h[i]),l=max(l,h[i]),sum[i]=sum[i-]+h[i];
while(l<=r){
Mid=(l+r)/;
if(check(Mid)) l=Mid+,ans=Mid;
else r=Mid-;
}
printf("%I64d\n",ans);
return ;
}
最新文章
- [半转]1px边框 移动端
- JOptionPane类提示框的一些常用的方法
- Software Testing hw2
- linux项目-之系统安装部署-cobbler
- jquery列表动画
- cover letter issues
- log实例
- BZOJ 1218: [HNOI2003]激光炸弹( 前缀和 + 枚举 )
- Android Stuido怎样查看快捷键冲突?
- ios之极光推送消息收到以后对消息的处理总结
- Linux - atexit()(注册终止)函数
- qemu-trustzone编译&;运行(包含linux内核的编译方法)
- Android简易实战教程--第五话《开发一键锁屏应用》
- 前后端分离djangorestframework——序列化与反序列化数据
- GSON中Java对象与JSON互相转换——(一)
- 为什么c++中,有时可以用类名直接访问非静态成员函数?
- IE8 AJAX 不能正常工作 解决办法
- train_test_split, 关于随机抽样和分层抽样
- IDEA Java开发常用插件
- Mybatis的mapper文件中$和#的用法及区别详解