题目id:20300
题目描述
鱼大大计划环华夏自驾游游玩一圈,在他的计划中,这次旅行将在\(m\)天内完成,预计游玩\(n\)个城市,每个城市游玩\(x\)天,然后赶路开车以均速去到下一个城市,现鱼大大从海洋城市出发,按游玩顺序先后给出每个城市和上一个城市之间的距离(\(km\)),问鱼大大每天至少赶路多少距离(\(km\))才能在\(m\)天内游玩所有城市?
解题思路
由于该题数据范围较大:
\(1\leq n\leq 10^{5}\)
\(1\leq a_i,x,m\leq 10^{15}\)
枚举应该(kěn dìng)会超时,所以我们该题使用时间复杂度为\(O(n\log v)\)的二分查找,其中\(v\)为每天最多赶的路程(既\(10^{15}km\)),多出来的\(n\)为每次\(check\)函数的时间复杂度。
由于求的是最小值,我们需要用如下二分查找模板:
while(l<r)
{
ll mid=(l+r)/2;
if(check(mid))r=mid;
else l=mid+1;
}
那我们如何编写\(check\)函数呢?
因为我们二分的是每天最少的赶路路程(\(km\)),所以我们遍历一遍路程数组,求出对于第\(i-1\)个城市到第\(i\)个城市按照当前速度\(v\ km/天\)需要\(x_i\)天赶完,最后的总天数即为
\(
\begin{equation*}
t=(\sum_{i=1}^nx_i)+(\sum_{i=1}^ny_i)
\end{equation*}
\)
其中\(y_i\)为每个城市的游玩天数。
另外,由于每天赶路的速度是整数,所以\(x_i\)需要向上取整。
综上所述,可得\(check\)函数如下:
bool check(ll mid)
{
ll cnt=0;
for(ll i=1;i<=n;++i)
cnt+=(ll)(ceil((double)(a[i])/mid));
return cnt<=m;
}
其中\(m\)已提前减去游玩天数。
AC Code
#include<bits/stdc++.h>
#define N 1000007
#define INF 1e18
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define IOS ios::sync_with_stdio(0),cin.tie(nullptr),cout.tie(nullptr)
using namespace std;
ll n,m,l,r=1e15,a[N];
bool check(ll mid)
{
ll cnt=0;
for(ll i=1;i<=n;++i)cnt+=(ll)(ceil((double)(a[i])/mid));
return cnt<=m;
}
int main()
{
IOS,cin>>n>>m;
for(ll i=1,day;i<=n;++i)cin>>a[i]>>day,m-=day;
while(l<r)
{
ll mid=(l+r)/2;
if(check(mid))r=mid;
else l=mid+1;
}
if(l==1e15)cout<<-1;
else cout<<l;
return 0;
}
标签:旅行,游玩,题解,ll,km,leq,城市,define
From: https://www.cnblogs.com/988176-/p/18332907