P3853 [TJOI2007]路标设置

时间:2023-01-01 14:33:25

传送门

思路:

  类似于数列分段的二分查找答案。设目前的 mid 是一个最小的“空旷指数”,那么在 sum 数组(路标数组)里每两个相邻间的路标距离一定要小于等于目前的 mid , 如果大于,那就必须使用一些路标去填补这个距离。

  两个路标之间距离大于 mid 又要分为两种情况:①两路标之间距离不能整除 mid ,则要放置 ( sum [ i+1 ] -sum [ i ] )/mid 个路标。②如果两路标之间距离能够整除 mid 则所放置的路标数要 -1 。

  每一次二分判断 mid 距离是否满足 cnt ≤ k :①如果≤, 则 mid 的距离可以再缩小;②如果>,则 mid 的距离要放大。

AC代码:

 

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#include<deque>
#include<stack>
#include<map>
#include<set>
using namespace std;
#define maxn 100100
long long sum[maxn],l,r,mid,cnt;//cnt记录在mid条件下,所需的路标数
long long len,n,k;
inline long long read()
{
    long long kr=1,xs=0;
    char ls;
    ls=getchar();
    while(!isdigit(ls))
    {
        if(ls=='-')
        kr=-1;
        ls=getchar();
    }
    while(isdigit(ls))
    {
        xs=(xs<<1)+(xs<<3)+(ls^48);
        ls=getchar();
    }
    return kr*xs;
}
inline bool check(long long u)
{
    cnt=0;
    for(long long i=1;i<=n+1;i++)
    {
        if(sum[i]-sum[i-1]>u)//如果两个路标之间的距离大于mid
        {
            cnt+=(sum[i]-sum[i-1])/u;//所需的路标数增加
            if((sum[i]-sum[i-1])%u==0)//如果能够整除
                cnt--;//路标数 -1
        }
    }
    if(cnt<=k) return true;
    return false;
}
int main()
{
    len=read();n=read();k=read();
    for(long long i=1;i<=n;i++)
        sum[i]=read();
    sum[0]=0;sum[n+1]=len;
    l=0;r=sum[n];
    while(l<r)
    {
        mid=l+r>>1;
        if(check(mid))
            r=mid;
        else l=mid+1;
    }//日常二分
    printf("%lld\n",l);//l为最终的mid  
return 0;
}