旅行 题解

题目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;
}
posted @ 2024-07-30 17:02  Firra3500  阅读(8)  评论(0编辑  收藏  举报