[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)$
View Code
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 }