Skip to main content
Original456 words2 min

题解:CF1810D Climbing the Tree

Summary

蜗牛白天上爬 a 米、夜里下滑 b 米,维护树高的可能区间。事件一给出某蜗牛用 n 天爬到顶,据此推出符合的树高上下界并与当前区间求交,若交集为空则信息矛盾、忽略。事件二给出树高询问天数,天数关于树高单调,分别用区间左右端点算出最少与最多天数,两者相等才能确定唯一答案,否则输出 -1。注意向上取整用整数公式,避免浮点精度问题。

解题思路​

设当前可能的树高范围为 [L,R][L,R]。

初始时,树高可能为任意正整数,所以令 L=1,R=∞L=1,R=\infty。

事件 1​

一只属性为 a,ba,b 的蜗牛声称花了 nn 天爬树。

设符合条件的树高范围为 [Hmin,Hmax][H_{min},H_{max}]。

前 n−1n-1 天,白天上爬 aa 米,晚上下滑 bb 米,每天爬 a−ba-b 米;最后 11 天最多爬 aa 米。所以 Hmax=(a−b)(n−1)+aH_{max}=(a-b)(n-1)+a 米。

爬了 nn 天意味着第 n−1n-1 天没有爬到树顶,同理 n−1n-1 天最多爬 (a−b)(n−2)+a(a-b)(n-2)+a 米。所以 Hmin=(a−b)(n−2)+a+1H_{min}=(a-b)(n-2)+a+1 米。

计算 [L,R][L,R] 和 [Hmin,Hmax][H_{min},H_{max}] 的交集,如果为空,说明该信息有冲突,直接忽略;否则树高范围需要同时满足这两个集合,即将 [L,R][L,R] 设为两者的交集。

事件 2​

一只属性为 a,ba,b 的蜗牛询问爬树所需天数。

当树高为 hh 米时,设所需天数为 nn 天。

最后 11 天爬 aa 米,还剩 h−ah-a 米;前面每天爬 a−ba-b 米,需要 ⌈h−aa−b⌉\left\lceil\frac{h-a}{a-b}\right\rceil 天。所以 n=⌈h−aa−b⌉+1n=\left\lceil\frac{h-a}{a-b}\right\rceil+1 天。

显然,当 h=Lh=L 时,所需天数最少;当 h=Rh=R 时,所需天数最多。如果两者相等,便可以得出精确的答案。

细节​

  • 在事件 11 中,当 n=1n=1 时,最小树高 Hmin=1H_{min}=1 米。
  • 在事件 22 中,所需天数至少为 11 天。
  • 使用 double 类型,可能会导致精度丢失。建议根据公式手写取上整函数:
⌈ab⌉=⌊a+b−1b⌋\left\lceil\frac{a}{b}\right\rceil=\left\lfloor\frac{a+b-1}{b}\right\rfloor

参考代码​

731 Bcpp
#include <bits/stdc++.h>
using namespace std;

using ll=long long;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int N=200005;
ll up(ll a,ll b){return (a+b-1)/b;}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin>>T;
while(T--)
{
ll L=1,R=inf;
int q;
cin>>q;
while(q--)
{
int op;
ll a,b,n;
cin>>op;
if(op==1)
{
cin>>a>>b>>n;
ll mn=(n==1?1:(a-b)*(n-2)+a+1);
ll mx=(a-b)*(n-1)+a;
if(mx<L||mn>R)
{
cout<<0<<' ';
}
else
{
cout<<1<<' ';
L=max(L,mn);
R=min(R,mx);
}
}
else
{
cin>>a>>b;
ll mn=max(up(L-a,a-b)+1,1ll);
ll mx=max(up(R-a,a-b)+1,1ll);
cout<<(mn==mx?mn:-1)<<' ';
}
}
cout<<'\n';
}
return 0;
}