题解:P14333 [JOI2021 预选赛 R2] 安全检查 / Safety Inspection
绿题?1h 才切?
Solution P14333
首先瞪一眼就知道是二分答案。然后考虑能否让所有工人在
下面称向右移
:::::warning[贪心问题
是否会出现样例
::::error[如果你不理解我在说什么] ::::
:::::
::::success[结论]
不会出现。
考虑以下情况:
和下面的情况对比:
显然下面的情况,工人
有人可能会说,万一工人
所以一个工人的工作位置必然是一段区间。
::::
::::warning[贪心问题
就像这样:
(两个人同时开始工作,同时在一个点工作,同时完成工作) ::::
::::success[结论] 不会!
因为你会发现:
这样第一个工人无需走
::::warning[贪心问题
::::success[结论] 很显然的结论:你还是尽量让他多干点活。 ::::
最后我们得到了一个贪心策略:模拟某个工人的过程,如果多这个位置不会超时(上一个位置
但是有可能有些位置任务实在太多了,导致很多工人只在这个点上干活都干不完。这样的情况我们加一个特判就能解决:考虑工人走到这个位置(前面什么都不干之后剩余时间为
注意边界:如果第
由于某些工人干活的过程中,一些位置的
::::success[
#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define fastio ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define ls (now<<1)
#define rs ((now<<1)|1)
#define int long long
using namespace std;
const int N=200005;
ll a[N],b[N],sum[N];
int n,m;
struct bittree{
ll tr[N];
int lowbit(int x){
return x&(-x);
}
void init(){
memset(tr,0,sizeof tr);
}
void update(int now,ll x){
while(now<=n){
tr[now]+=x;
now+=lowbit(now);
}
}
ll qsum(int now){
ll res=0;
while(now){
res+=tr[now];
now-=lowbit(now);
}
return res;
}
ll query(int l,int r){
return qsum(r)-qsum(l-1);
}
}tr;
bool check(ll t){
int lst=1,cnt=0;
tr.init();
for(int i=1;i<=n;i++){
tr.update(i,b[i]);
}
cnt=1;
for(int i=1;i<=n;i++){
if(a[i]+tr.query(lst,i)>t){
ll r=(t-(a[i]+tr.query(lst,i-1)));
if(r>0)tr.update(i,-r);
if(tr.query(i,i)){
r=t-a[i];
if(r<=0)return false;
ll w=tr.query(i,i);
cnt+=w/r;
tr.update(i,-(w/r*r));
lst=i;
if(i!=n||tr.query(i,i)!=0)cnt++;
}
}
}
return cnt<=m;
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
fastio;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];
tr.update(i,b[i]);
}
ll l=1,r=1000000000000000000,ans=0;
while(l<=r){
ll mid=(l+r)>>1;
if(check(mid)){
ans=mid;
r=mid-1;
}
else l=mid+1;
}
cout<<ans<<'\n';
return 0;
}
::::