1 条题解

  • 0
    @ 2025-8-24 21:37:09

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Egg_eating_master
    Always break; Never continue; | 我吃了个蛋

    搬运于2025-08-24 21:37:09,当前版本为作者最后更新于2020-09-12 17:13:50,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    UpdateUpdate2020.9.192020.9.19,修复了大家指出的一个错误

    其实我觉得吧,这题不用像大家说的,枚举左点,二分右点

    题目问的是最多可以访问多少地标。稍稍分析可知,多访问一个路标,时间必定不会减少,显然这具有单调性质。于是很自然的可以想到去二分路标的个数呀QwQQwQ

    先将所有路标的位置排序。要尽量使用时最少,那么我访问的任意两个路标之间都不能有其他的东西。(因为如果我访问的两个路标之间还有路标,那我还不如把这个路标顺便一起访问了呢)

    那么,在存储路标位置的数组中,只要排好序,我访问的路标就一定是下标相邻的。

    二分能访问到的路标个数,枚举右端点(当然左端点也行),判断这个区间是否能在tt的时间内访问完成。

    最后右端点枚举完了,如果还没有找到解,那就证明当前二分的这个路标个数不行。

    一直二分就行了。

    #include<bits/stdc++.h>
    using namespace std;
    int t,n;
    int a[100001];
    bool check(int x){//判断函数,表示的是能否访问到x个路标
    	for(int r=x;r<=n;r++){//枚举右端点
    		int l=r-x+1;
    		if(a[r]<=0)//如果右端点在原点左边,就要一直向左走
    		    if(-a[l]<=t)return 1;//根据题意判断即可,可以就直接返回true
    		if(a[l]>=0)//如果左端点在原点右边,就要一直向右走
    		    if(a[r]<=t)return 1;//同上
    		if(a[l]<=0&&a[r]>=0)//如果这段区间横跨了原点
    		    if(min(a[r],-a[l])+a[r]-a[l]<=t)return 1;//那么我一定是先去距离原点短的那一边,再走到另一边
    	}
    	return 0;//如果整个循环执行完,没有找到可行解,那就返回false
    }
    int main(){
    	cin>>t>>n;
    	for(int i=1;i<=n;i++)
    	    cin>>a[i];
    	sort(a+1,a+1+n);//给所有路标位置排序
    	int l=-1,r=n+1;//由于能访问的路标数量可能为0~n,所以把左边界设为1,右边界设为n+1,就可以保证二分到所有解
    	while(l+1<r){//这里写l+1<r是为了防止最后l,r出现交叉的情况,即l>r
    		int mid=(l+r)>>1;
    		if(check(mid))l=mid;
    		else r=mid;
            //更新l,r的值时写mid而不是mid+1或mid-1,也是为了防止最后l>r
    	}
    	cout<<l<<endl;最后输出l
    	return 0;//Happy ending~
    } 
    
    • 1

    信息

    ID
    1407
    时间
    1000ms
    内存
    125MiB
    难度
    3
    标签
    递交数
    0
    已通过
    0
    上传者