当前位置: 首页 > news >正文

(贪心、数学、二分)洛谷 P9755 CSPS2023 种树 题解

题意

题目传送门,建议前往阅读题面、样例和部分分。

思路

题目明示我们,不能直接模拟种树和树的生长过程——答案不超过 10910^9109。可以考虑决定种树的次序然后 O(n)O(n)O(n) 种树,外面套一个二分答案 O(log⁡V)O(\log V)O(logV)

问题转变为能不能在 midmidmid 天内完成。

发现特殊性质 A 是 ci=0c_i=0ci=0,那么树 iii 的生长速度是每天 bib_ibi。我们容易计算,至少要在哪一天要种下树 iii,才能使得 iii 长到 aia_iai。记这个限制为 latei=mid−⌈aibi⌉late_i=mid-\left\lceil \frac{a_i}{b_i} \right\rceillatei=midbiai

那么这里有个贪心,我们对 lateilate_ilatei 排序,优先种 lateilate_ilatei 小的显然是优的。

怎么种树呢?题目说,你每天可以选择一个未种树且与某个已种树的地块直接邻接的地块种树。因此对于目标种树点 iii,每次往上跳直到遇到第一个已经被种树的节点,用一个栈记录经过的结点,按照出栈序种树。我们在 nnn 的时间内种完所有树。

由于不会重复种树,种树均摊下来时间复杂度 O(n)O(n)O(n),排序那里 O(nlog⁡n)O(n\log n)O(nlogn)

bool cmp(node x,node y)
{return x.lat<y.lat;
}
...
memset(vis,0,sizeof(vis));
vis[0]=1;//1的父亲是0 
sort(p+1,p+n+1,cmp);
ll tick=0;
for(int i=1;i<=n;i++)
{ll u=p[i].ord;if(vis[u])continue;vis[u]=1;stk.push(u);while(1){if(vis[fat[u]])break;u=fat[u];stk.push(u);vis[u]=1;}while(!stk.empty())//树上从上往下种树{ll tem=stk.top();stk.pop();tick++;if(lat[tem]<tick)return 0;}
}

我们发现树 iii 的生长量很猎奇:max⁡{1,bi+xci}\max\{1,b_i+xc_i\}max{1,bi+xci},其中 xxx 表示整个种树过程的第 xxx 天,也就是说这棵树某天 lll 开始到 rrr 天结束一直生长。于是考虑快速计算 cal(i,l,r)

如果 ci≥0c_i\ge 0ci0cal(i,l,r) =∑x=lrbi+xci=(r−l+1)bi+sum(l,r)ci=\displaystyle\sum _{x=l}^rb_i+xc_i=(r-l+1)b_i+sum(l,r)c_i=x=lrbi+xci=(rl+1)bi+sum(l,r)ci

其中 sum(l,r)=(l+r)×(r−l+1)÷2sum(l,r)=(l+r)\times(r-l+1)\div 2sum(l,r)=(l+r)×(rl+1)÷2,等差数列求和容易 O(1)O(1)O(1) 计算。

ci<0c_i<0ci<0 的时候一次函数 f(x)=bi+xcif(x)=b_i+xc_if(x)=bi+xci 可能跌到 111 以下,考虑计算 xxx 在哪里最后一次 f(x)≥1f(x)\ge 1f(x)1f(x)=bi+xci≥1f(x)=b_i+xc_i\ge 1f(x)=bi+xci1,解得 x≤pos=⌊1−bici⌋x\le pos=\left\lfloor \frac{1-b_i}{c_i} \right\rfloorxpos=ci1bi

于是 x≤posx\le posxposmax⁡{1,bi+xci}\max\{1,b_i+xc_i\}max{1,bi+xci} 为后者,否则前者。若 l≤pos≤rl\le pos\le rlposr,则 cal(i,l,r) =(pos−l+1)bi+sum(l,pos)ci+r−pos=(pos-l+1)b_i+sum(l,pos)c_i+r-pos=(posl+1)bi+sum(l,pos)ci+rpos。分类讨论 posposposl,rl,rl,r 的大小关系即可。

ll cal(ll id,ll l,ll r)
{if(c[id]>=0)return (r-l+1)*b[id]+sum(l,r)*c[id];ll pos=(1-b[id])/c[id];if(pos<l)return r-l+1;if(pos>=r)return (r-l+1)*b[id]+sum(l,r)*c[id];return (pos-l+1)*b[id]+sum(l,pos)*c[id]+r-pos;
}

考虑重新计算此处的 lateilate_ilatei。我们发现钦定了一个限制天数 midmidmid,相当于 r=midr=midr=mid,我们想要计算 cal(i,l,mid) ≥ai\ge a_iai 的最小的 lll,即要求 lateilate_ilatei。我们发现 lll 越大 cal 计算结果越小,具有单调性,因此这个 lll 可以二分得到。

for(int i=1;i<=n;i++)
{ll tem=cal(i,1,mid);if(cal(i,1,mid)<a[i])return 0;//在限制内不能长到 a[i]ll il=1,ir=n,ret=1;//因为在n的时间内种完所有树,因此l的二分值域只有[1,n]while(il<=ir){ll imid=(il+ir)>>1;if(cal(i,imid,mid)>=a[i])ret=imid,il=imid+1;else ir=imid-1;}lat[i]=ret;p[i]=(node){ret,i};
}

时间复杂度 O(nlog⁡Vlog⁡n)O(n\log V\log n)O(nlogVlogn)

到这里我们发现,这题有贪心思想还有二分,还有可爱的小奥,综合性比较高捏!

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define i8 __int128
const ll N=1e5+9;
ll n;
vector<ll>G[N];
ll a[N],b[N],c[N];
i8 sum(ll l,ll r)
{return (l+r)*(r-l+1)/2;
}
i8 cal(ll id,ll l,ll r)
{if(c[id]>=0)return (r-l+1)*b[id]+sum(l,r)*c[id];ll pos=(1-b[id])/c[id];if(pos<l)return r-l+1;if(pos>=r)return (r-l+1)*b[id]+sum(l,r)*c[id];return (pos-l+1)*b[id]+sum(l,pos)*c[id]+r-pos;
}
ll fat[N];
void dfs(ll u,ll fa)
{fat[u]=fa;for(auto v:G[u]){if(v==fa)continue;dfs(v,u);}
}
struct node
{i8 lat;ll ord;
}p[N];
i8 lat[N];
bool cmp(node x,node y)
{return x.lat<y.lat;
}
bool vis[N];
stack<ll>stk;
bool check(ll mid)
{while(!stk.empty())stk.pop();for(int i=1;i<=n;i++){ll tem=cal(i,1,mid);if(cal(i,1,mid)<a[i])return 0;ll il=1,ir=n,ret=1;while(il<=ir){ll imid=(il+ir)>>1;if(cal(i,imid,mid)>=a[i])ret=imid,il=imid+1;else ir=imid-1;}lat[i]=ret;p[i]=(node){ret,i};}memset(vis,0,sizeof(vis));vis[0]=1;//1的父亲是0 sort(p+1,p+n+1,cmp);ll tick=0;for(int i=1;i<=n;i++){ll u=p[i].ord;if(vis[u])continue;vis[u]=1;stk.push(u);while(1){if(vis[fat[u]])break;u=fat[u];stk.push(u);vis[u]=1;}while(!stk.empty()){ll tem=stk.top();stk.pop();tick++;if(lat[tem]<tick)return 0;}}return 1;
}
int main()
{scanf("%lld",&n);for(int i=1;i<=n;i++)scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);for(int i=1;i<n;i++){ll u,v;scanf("%lld%lld",&u,&v);G[u].push_back(v);G[v].push_back(u);}dfs(1,0);ll l=n,r=1e9,ans=1e9;while(l<=r){ll mid=(l+r)>>1;if(check(mid))ans=mid,r=mid-1;else l=mid+1;}printf("%lld",ans);return 0;
}

文章转载自:

http://KGJkKg3v.jcfdk.cn
http://FkOfOx7L.jcfdk.cn
http://44dDivQg.jcfdk.cn
http://E0RbvVPW.jcfdk.cn
http://OqkgjG8U.jcfdk.cn
http://LBonIvHj.jcfdk.cn
http://MsUjNP77.jcfdk.cn
http://CXB6foTc.jcfdk.cn
http://Kyg4DV95.jcfdk.cn
http://XKhxClui.jcfdk.cn
http://y13d9yqq.jcfdk.cn
http://ttEB0UNi.jcfdk.cn
http://6RVxKyJi.jcfdk.cn
http://Eecoatne.jcfdk.cn
http://jT2mxAV5.jcfdk.cn
http://TPG1U2IM.jcfdk.cn
http://fyWYDCcD.jcfdk.cn
http://eRrDYeQr.jcfdk.cn
http://QkeG6bEQ.jcfdk.cn
http://SxVHaLjB.jcfdk.cn
http://BnokIcZC.jcfdk.cn
http://n7nDKYAE.jcfdk.cn
http://0EwKjb2z.jcfdk.cn
http://vPuH3Jcm.jcfdk.cn
http://OAfrqtYM.jcfdk.cn
http://Oef94EWq.jcfdk.cn
http://eVv4shXB.jcfdk.cn
http://ZvaZmymK.jcfdk.cn
http://1YXJPPFq.jcfdk.cn
http://C5jFxhnp.jcfdk.cn
http://www.dtcms.com/a/376231.html

相关文章:

  • 反相放大器电路和T形网络反相放大电路与仿真
  • C++的诗行:一文读懂C++的继承机制
  • ubuntu 22 安装轻量级桌面Xfce并使用xrdp远程桌面连接
  • PixVerse -免费在线AI视频生成工具
  • 赋能数字孪生:Paraverse平行云实时云渲染平台LarkXR,提供强大的API与SDK用于二次开发和深度集成
  • 【JVS更新日志】低代码、APS排产、物联网、企业计划9.10更新说明!
  • 一维差分(扫描线)基础篇
  • Umi-OCR:Windows7和Linux上可免费离线使用的OCR应用!
  • 系统是Rocky Linux 9.6,用比对工具compare beyond 工具中私钥连接连不上
  • 计算机毕设 java 高校饭堂点餐系统 基于微信小程序 + SSM 的高校餐饮服务平台 Java+MySQL 的点餐与运营系统
  • 高效计算的源泉:深入浅出冯诺依曼模型与操作系统的管理艺术 —— 构建稳定、高效的应用基石 【底层逻辑/性能优化】
  • CSS 继承 (Inheritance)
  • 计算机视觉cv2入门之实时人脸检测
  • 增值税电子发票查验-财政票据查验接口-全电票查验api
  • 【第23话:定位建图】SLAM后端优化方法详解
  • 异步处理(前端面试)
  • ArKTS登录界面开发
  • 用于树莓派的sd卡格式是什么适合,它现在是exFAT,需要是FAT32吗
  • 使用Qoder 改造前端UI/UE升级改造实践:从传统界面到现代化体验的华丽蜕变
  • HTML HTML基础(4)
  • 【Matlab】-- 机器学习项目 - 基于XGBoost算法的数据回归预测
  • 在企业中风控规则引擎的解决方案是什么?
  • StarRocks导入数据-使用 Broker Load 进行异步导入
  • GaussDB闪回技术
  • OpenResty 配合 Lua 脚本的使用
  • 浅聊一下Redisson分布式锁
  • kdump使用方法和场景介绍
  • 提示词工程深度实践:从基础原理到生产级应用优化
  • [硬件电路-176]:光电二极管利用的二极管的漏电流与光强的线性关系,通过电流大小推算光强的大小
  • 基于单片机的电机交流调速系统设计(论文+源码)