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;
}
posted @ 2021-09-29 16:30  QuantAsk  阅读(34)  评论(0编辑  收藏  举报