[] CF505E

题意:给定 $n$ 个数 $h_{1 \dots n}$。你需要进行 $m$ 轮操作,每轮操作为 $k$ 次修改,每次修改可以选择一个数 $h_i$ 修改为 $\max(h_i - p, 0)$。每轮操作后每个 $h_i$ 将会被修改为 $h_i + a_i$。你需要最小化最终 $h_{1 \dots n}$ 中的最大值。$n \le 10^5$,$m \le 5 \times 10^3$,$k \le 10$。

正难则反,每次找到最容易失败点 $+p$ 即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#define int long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int MAXN=100001;
priority_queue<pii> que;
int a[MAXN],N,M,k,p,h[MAXN];
int Ans[MAXN],cnt=0;
bool check(int Lim){
    while(!que.empty()) que.pop();memset(Ans,0,sizeof(Ans));cnt=0;
    for(int i=1;i<=N;i++) if(Lim-a[i]*M<h[i]) que.push(mp(-(Lim/a[i]),i));
    for(int i=1;i<=M;i++){
        bool ff=0;
        for(int j=1;j<=k;j++){
            if(que.empty()){ff=1;continue;}
            int res=-que.top().fi,id=que.top().se;que.pop();
            if(res<i) return 0;Ans[id]++;
            int w=(Lim+p*Ans[id])/a[id];
            if(w<M) que.push(mp(-w,id));
            ++cnt;
        }if(ff) break;
    }
    for(int i=1;i<=N;i++){
        int w=Lim+p*Ans[i]-M*a[i];
        if(w>=h[i]) continue;
        cnt+=((h[i]-w-1)/p)+1;
    }return cnt<=M*k;
}
signed main(){
    //freopen("1.in","r",stdin);
    N=read(),M=read(),k=read(),p=read();
    for(int i=1;i<=N;i++) h[i]=read(),a[i]=read();
    int l=0,r=1e15,res;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid)) res=mid,r=mid-1;
        else l=mid+1;
    }printf("%lld\n",res);return 0;
}/*
  3 1 2 5
  10 10
  10 10
  15 2
  */
View Code

相关文章: