[cf505E]Mr. Kitayuta vs. Bamboos

二分答案,设$s_{i,j}$表示第$i$天对竹子$j$的操作次数,$h_{i,j}$表示第$i$天结束时竹子$j$的高度,则$h_{i,j}=\max(h_{i-1,j}-ps_{i,j},0)+a_{j}$,合法当且仅当$h_{0,i}=h_{i}$且$h_{m,i}\le ans$
令$h'_{i,j}$表示若$h_{i,j}=h'_{i,j}$,转移后满足$h'_{m,j}\le ans$中最大的,转移:若$h'_{i,j}\ge a_{j}$,则$h'_{i-1,j}=ps_{i,j}+h'_{i,j}-a_{j}$,否则无解
合法当且仅当$h'_{m,i}=ans$、$h'_{0,i}$有解且$h'_{0,i}\ge h_{i}$,有解的必要条件为$h'_{i,j}\ge a_{j}$,因此转移就不需要特判
 这样就可以贪心,初始$s_{i,j}=0$,每一次选择在当前的状态下$\max_{h'_{i,j}<a_{j}}i$最大的$j$并令$s_{now,j}+=1$,用堆维护即可,时间复杂度为$o((mk+n)\log_{2}n\log_{2}ans)$
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 100005
 4 #define ll long long
 5 priority_queue<pair<ll,int> >q;
 6 int n,m,k,p,h[N],a[N];
 7 ll f[N];
 8 ll calc(int k){
 9     if (f[k]/a[k]<m)return f[k]/a[k];
10     if (f[k]-1LL*m*a[k]<h[k])return m;
11     return m+1;
12 }
13 bool pd(ll s){
14     for(int i=1;i<=n;i++)f[i]=s;
15     while (!q.empty())q.pop();
16     for(int i=1;i<=n;i++)q.push(make_pair(-calc(i),i));
17     for(int i=1;i<=m;i++){
18         for(int j=1;j<=k;j++){
19             int x=q.top().second;
20             q.pop();
21             f[x]+=p;
22             q.push(make_pair(-calc(x),x));
23         }
24         if (-q.top().first<=i)return 0;
25     }
26     return (-q.top().first>m);
27 }
28 int main(){
29     scanf("%d%d%d%d",&n,&m,&k,&p);
30     for(int i=1;i<=n;i++)scanf("%d%d",&h[i],&a[i]);
31     ll l=0,r=1e13;
32     for(int i=1;i<=n;i++)l=max(l,1LL*a[i]);
33     while (l<r){
34         ll mid=(l+r>>1);
35         if (pd(mid))r=mid;
36         else l=mid+1;
37     }
38     printf("%lld",l);
39 }
View Code

 

posted @ 2020-08-26 09:02  PYWBKTDA  阅读(169)  评论(0编辑  收藏  举报