Codeforces 506C. Mr. Kitayuta vs. Bamboos 题解
题目链接:C. Mr. Kitayuta vs. Bamboos
题目大意:你的庄园里用n棵竹子,每棵竹子有一个初始高度hi,每天会往上张ai,你非常不喜欢这些竹子长得很高,所以你要使用魔法将这些竹子给削下来,你会在竹园中待m天,每天你会施展k次魔法,每一次魔法可以让一棵竹子的高度变为max(0,h−p)(h为当前这棵竹子的高度),你想知道在m天后竹园中竹子最高高度最小是多少。
题解:一看到最高高度最小
,直接想到二分答案,那么关键就是 check 函数怎么写了,很容易可以想到一个很假的贪心思路,就是把每棵竹子用最小的次数给削下来,但是这里就出问题了,因为你不能把竹子给打到地底下,这就会导致你在打每一棵竹子时会有一个时间限制,这样一个限制下来,似乎就没法做了(当然,官方题解也提供了一种这样走下去的思路,可是我没看懂,果然还是太菜了嘤嘤嘤)。
“正难则反”,所以考虑对问题进行转化。令二分的答案为x,我们把每一棵竹子最终的高度都定为x(因为它不可能超过x),那么从第m天开始到第一天为止,竹子每天就不是往天上长,而是往地下钻,而每一次魔法操作则是把竹子给拉上来,可以这样理解,假设我们已经知道了所有的操作并且把它们做成了视频,然后倒着播放,那么限制条件就变为了:
- 每一棵竹子在每个时刻的高度都不能小于0(因为竹子最低高度就是0)
- 第i棵竹子在操作完之后的高度不能小于hi(如果大于的话可以从最终高度上减,容易发现这是没有问题的)
然后这就方便了,可以直接用堆维护将要掉到0以下的最小天数,然后贪心地做就可以了。
时间复杂度:O((n+mk)lognlog(hmax+amaxm)),可以粗略的认为是O(nlog2n)。
代码:
#include <queue> #include <cstdio> #include <iostream> using namespace std; void read(int &a){ a=0; char c=getchar(); while(c<'0'||c>'9'){ c=getchar(); } while(c>='0'&&c<='9'){ a=(a<<1)+(a<<3)+(c^48); c=getchar(); } } const int Maxn=100000; typedef long long ll; int n,m,k,p; struct Bamboo{ int h,a; }a[Maxn+5]; struct Node{ ll day; int id; friend bool operator <(Node p,Node q){ if(p.day==q.day){ return p.id<q.id; } return p.day<q.day; } friend bool operator >(Node p,Node q){ if(p.day==q.day){ return p.id>q.id; } return p.day>q.day; } Node(ll _day=0,int _id=0){ day=_day; id=_id; } }; priority_queue<Node,vector<Node>,greater<Node> > q; int tim[Maxn+5]; bool check(ll x){ while(!q.empty()){ q.pop(); } for(int i=1;i<=n;i++){ if(x-1ll*a[i].a*m<a[i].h){ q.push(Node(x/a[i].a,i)); tim[i]=0; } } for(int i=1;!q.empty()&&i<=m;i++){ for(int j=1;!q.empty()&&j<=k;j++){ Node u=q.top(); q.pop(); if(u.day<i){ return 0; } tim[u.id]++; if(x+1ll*tim[u.id]*p-1ll*a[u.id].a*m<a[u.id].h){ q.push(Node((x+1ll*tim[u.id]*p)/a[u.id].a,u.id)); } } } return q.empty(); } int main(){ read(n),read(m),read(k),read(p); ll left=0,right=0; for(int i=1;i<=n;i++){ read(a[i].h); read(a[i].a); right=max(right,a[i].h+1ll*m*a[i].a); } while(left<right){ ll mid=(left+right)>>1; if(check(mid)){ right=mid; } else{ left=mid+1; } } cout<<left<<endl; return 0; }
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET 9 new features-C#13新的锁类型和语义
· Linux系统下SQL Server数据库镜像配置全流程详解
· 现代计算机视觉入门之:什么是视频
· 你所不知道的 C/C++ 宏知识
· 聊一聊 操作系统蓝屏 c0000102 的故障分析
· 不到万不得已,千万不要去外包
· C# WebAPI 插件热插拔(持续更新中)
· 会议真的有必要吗?我们产品开发9年了,但从来没开过会
· 如何打造一个高并发系统?
· 【译】我们最喜欢的2024年的 Visual Studio 新功能