文章目录
- 题目
- 思路
- 代码
题目
思路
首先最大值最小考虑二分,假设我们检验 xxx
但是发现检验比较难写
尝试从图像分析
那么画出来图像大致如下:
然后我们发现可以将图像上移末端重合至 (m,x)(m,x)(m,x) 点
那么只需要倒推改成每天减小 aia_iai? 高度,每天有 kkk 次机会增加 ppp,保证初始高度大于hih_ihi? 即可
然后首先可以想到一个类似堆的做法,每次要死了就加,没来得及加的机会存下来
最后调整高度
时间复杂度 O(mklognlogA)O(mklog nlogA)O(mklognlogA)
发现可以更简单在每个必死时间点存储,
倒推要死的时候增加
最后调整高度就可以不用堆
时间复杂度 O(mklogA)O(mklogA)O(mklogA)
代码
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
int read(){
bool f=0;int x=0;char c=getchar();while(c<'0'||'9'<c){
if(c=='-')f=1;c=getchar();}while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();return !f?x:-x;
}
#define mp make_pair
const int MAXN=100000;
const int INF=0x3f3f3f3f;
typedef pair<int,int> pii;
LL n,m,k,p;
LL h[MAXN+5],a[MAXN+5];
queue<pii> q[MAXN+5];
bool check(LL x){
for(int i=1;i<=m;i++)while(!q[i].empty())q[i].pop();for(int i=1;i<=n;i++){
LL s=x/a[i]+1;if(s<=m) q[s].push(mp(i,0));}for(int i=1,c=0;i<=m;i++,c+=k){
while(!q[i].empty()){
if(!c) return 0;c--;pii u=q[i].front();q[i].pop(),u.second++;LL s=(u.second*p+x)/a[u.first]+1;if(s<=m) q[s].push(u);}}LL s=0;for(int i=1;i<=n;i++)s+=(max(h[i]+a[i]*m-x,0ll)+p-1)/p;return s<=m*k;
}
int main(){
//freopen("bamboo.in","r",stdin);//freopen("bamboo.out","w",stdout);n=read(),m=read(),k=read(),p=read();LL L=0,R=0;for(int i=1;i<=n;i++)h[i]=read(),a[i]=read(),R=max(R,h[i]+m*a[i]);while(L+1<R){
LL Mid=(L+R)>>1;if(check(Mid)) R=Mid;else L=Mid;}printf("%lld\n",R);return 0;
}