专栏文章
题解:AT_abc395_f [ABC395F] Smooth Occlusion
AT_abc395_f题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miq3ek2b
- 此快照首次捕获于
- 2025/12/03 22:18 3 个月前
- 此快照最后确认于
- 2025/12/03 22:18 3 个月前
题意
有两个长度为 的序列 和 ,每次操作可以把一个正数减一,问最少经过次操作使得:
- 存在 使所有 。
- 序列中相邻两个数的差小于等于 。
思路
这道题可以二分答案去做。
只需要确定 ,答案就是所有数字的总和减去 。
二分答案 ,下界是 ,上界是 。
设 分别表示操作完后的 和 。因为 ,所以只要一个确定了,另一个也确定,那我们就只考虑 。
因为每次操作只能减少,所以有 。
对于 推出 。
又因为每个数都要大于等于 且小于等于 。所以 的范围是区间 。
对每个 ,记录它的取值区间左端点 和右端点 。
第 个数的取值区间必须是两个约束的交集:
- 自身的区间 。
- 能够和前一个数的差不超过 ,即必须落在区间 内。
因此,对每个 ,。
如果对于某个 ,,说明不合法。check 函数就是这样写的。
AC Code
CPP#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
int n,x,u[N],d[N];
bool check(int H) {
int L=max(0ll,H-d[1]),R=min(u[1],H);
if(L>R) return 0;
for(int i=2;i<=n;i++){
int curL=max(0ll,H-d[i]),curR=min(u[i],H);
curL=max(curL,L-x),curR=min(curR,R+x);
if(curL>curR) return 0;
L=curL,R=curR;
}
return 1;
}
signed main() {
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>x;
int sum=0;
for(int i=1; i<=n; i++) cin>>u[i]>>d[i];
for(int i=1; i<=n; i++) sum+=u[i]+d[i];
int maxn=1145141919810ll;
for(int i=1; i<=n; i++) maxn=min(maxn,u[i]+d[i]);
int l=0,r=maxn,anss=0;
while(l<=r) {
int mid=(l+r)/2;
if(check(mid)) anss=mid,l=mid+1;
else r=mid-1;
}
cout<<sum-n*anss;
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...