[] 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 */