[CF505E] Mr.Kitayutavs.Bamboos
https://www.luogu.com.cn/problem/CF505E
最小化最大值肯定是二分答案
但是直接考虑貌似不太好做
考虑反过来,二分一个最大值为X,表示一开始每个位置高度都是X
每次
+
a
[
i
]
+a[i]
+a[i]改为每次
X
−
a
[
i
]
X-a[i]
X−a[i],然后修改
−
P
-P
−P改为
+
P
+P
+P “拔高”
然后看最后是不是每个位置上的值都
>
=
h
i
>=h_i
>=hi
注意中途不能让值减到负数(即超过最大值X)
拿个堆维护所有在当前状态下
最
后
高
度
<
=
h
i
的
位
置
,
如
果
一
直
减
,
减
到
<
0
需
要
的
天
数
最后高度<=h_i的位置,如果一直减,减到<0需要的天数
最后高度<=hi的位置,如果一直减,减到<0需要的天数
倒过来,从最后一天考虑每天的“拔高”名额应该分给谁
然后按照这个小根堆从小到大取出k个
然后再看
具体看代码吧
code:
#include<bits/stdc++.h>
#define ll long long
#define N 100050
using namespace std;
int n, m, k, p, h[N], a[N], c[N];
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;
int check(ll X) {
memset(c, 0, sizeof c);
while(q.size()) q.pop();
for(int i = 1; i <= n; i ++)
if(X - 1ll * a[i] * m < h[i]) q.push(make_pair(X / a[i], i));
for(int i = 1; i <= m && q.size(); i ++) {
for(int j = 1; j <= k && q.size(); j ++) {
int d = q.top().first, id = q.top().second; q.pop();
if(d < i) return 0;
c[id] ++;
if(X + 1ll * c[id] * p - 1ll * a[id] * m < h[id])
q.push(make_pair((X + 1ll * c[id] * p) / a[id], id));
}
}
return !q.size();
}
int main() {
scanf("%d%d%d%d", &n, &m, &k, &p);
for(int i = 1; i <= n; i ++) scanf("%d%d", &h[i], &a[i]);
ll l = 0, r = 1e18;
while(l + 1 < r) {
ll mid = (l + r) >> 1; //printf("%lld %lld\n", l, r);
if(check(mid)) r = mid;
else l = mid;
}
printf("%lld", r);
return 0;
}