CF505E-Mr. Kitayuta vs. Bamboos【贪心,二分】
正题
题目链接:https://www.luogu.com.cn/problem/CF505E
题目大意
开始一个长度为\(n\)的序列\(h\),\(m\)天每天你可以\(k\)次选择一个\(h_i\)让它等于\(h_i=max\{h_i-p,0\}\),然后结束时让每个\(h_i=h_i+a_i\),要求使得最后最大的\(h\)值最小。
\(1\leq n\leq 10^5,1\leq m\leq 5\times 10^3,1\leq k\leq 10\)
解题思路
这个好像是以前WC还是APIO讲课的题了。
首先最大值最小直接上二分,然后考虑贪心做。
不过正着做不太好做,考虑倒着。首先因为每次减法减去的值都是一样的,所以如果有一株的高度大于\(p\)那么我们显然没有必要剪高度小于\(p\)的,因为这样会浪费。
设答案为\(H\),那么开始我们就让所有草的高度都是\(H\),然后每次所有的草高度减少\(a_i\),然后你可以\(k\)次拔高一棵草的高度\(k\)。要求全程没有草的高度小于零且最后第\(i\)棵草的高度都不小于\(h_i\)。
那么考虑如果一棵草不用再管高度都不会小于\(h_i\)那么显然不需要管这棵了,否则剪它肯定不会,为了满足条件我们肯定是减去最快小于\(0\)的那棵草。
时间复杂度:\(O(\log L(n\log n+mk\log n))\)
\(code\)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
#define mp(x,y) make_pair(x,y)
using namespace std;
const ll N=1e5+10;
ll n,m,k,p,h[N],a[N],w[N];
priority_queue<pair<ll,ll> > q;
bool check(ll H){
while(!q.empty())q.pop();
for(ll i=1;i<=n;i++)
if(H-a[i]*m<h[i])w[i]=H,q.push(mp(-H/a[i],i));
for(ll i=1;i<=m;i++)
for(ll j=1;j<=k;j++){
if(q.empty())return 1;
ll z=-q.top().first;
ll x=q.top().second;
if(z-i<0)return 0;
q.pop();w[x]+=p;
if(w[x]-a[x]*m<h[x])
q.push(mp(-w[x]/a[x],x));
}
if(q.empty())return 1;
return 0;
}
signed main()
{
scanf("%lld%lld%lld%lld",&n,&m,&k,&p);
for(ll i=1;i<=n;i++)scanf("%lld%lld",&h[i],&a[i]);
ll l=0,r=1e9*(m+10);
while(l<=r){
ll mid=(l+r)>>1;
if(check(mid))r=mid-1;
else l=mid+1;
}
printf("%lld\n",l);
return 0;
}