CF505E Mr. Kitayuta vs. Bamboos 二分+贪心
二分最大值,然后考虑如何处理.
正着做很难,因为每次减掉 $p$ 后还要与 0 取 max,但是倒着做就会容易很多.
先将所有数的高度都置为 $mid$,那么就有两种操作:
1. -a[i]
2. +p
显然每次减掉 $a[i]$ 后不可以小于 0,因为如果减掉 $a[i]$ 后小于 0 的话意味着正着做到这一步没有与 0 取max.
那么减掉 $a[i]$ 后小于 0 的话就要加上 p.
我们贪心给最需要加上 p 的位置加上 p (即最快小于 0 的位置),然后如果 +p 操作不够的话就不合法.
如果合法,最终每个数的大小都要大于等于 $h_{i}$.
整个贪心过程用堆维护即可(实际上我们在堆中维护的是最小小于 $h_{i}$ 的时刻,不过反正都一样)
code:
#include <cstdio>
#include <cstring>
#include <queue>
#define N 100009
#define ll long long
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
int n,m,K,P;
int h[N],a[N],c[N];
struct node {
int id,day;
node(int id=0,int day=0):id(id),day(day){}
bool operator<(const node b) const {
return day>b.day;
}
};
priority_queue<node>q;
int check(ll val) {
memset(c,0,sizeof(c));
while(!q.empty()) q.pop();
for(int i=1;i<=n;++i) {
if(val-1ll*a[i]*m<h[i]) {
q.push(node(i,val/a[i]));
}
}
for(int i=1;i<=m&&!q.empty();++i) {
for(int j=1;j<=K&&!q.empty();++j) {
node e=q.top(); q.pop();
if(e.day<i) return 0;
++c[e.id];
if(val-1ll*a[e.id]*m+1ll*c[e.id]*P<h[e.id]) {
q.push(node(e.id,(val+1ll*c[e.id]*P)/a[e.id]));
}
}
}
return q.empty();
}
int main() {
// setIO("input");
scanf("%d%d%d%d",&n,&m,&K,&P);
ll l=1,r=0,mid,ans=0;
for(int i=1;i<=n;++i) {
scanf("%d%d",&h[i],&a[i]);
r=max(r,1ll*m*a[i]+h[i]);
}
while(l<=r) {
mid=(l+r)>>1;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%lld\n",ans);
return 0;
}

浙公网安备 33010602011771号