• 蓝桥杯省赛 区间移位(二分+玄学贪心)


    问题描述
      数轴上有n个闭区间D1,…,Dn。其中区间Di用一对整数[ai, bi]来描述,满足ai < bi。已知这些区间的长度之和至少有10000。所以,通过适当的移动这些区间,你总可以使得他们的“并”覆盖[0, 10000]——也就是说[0, 10000]这个区间内的每一个点都落于至少一个区间内。
      你希望找一个移动方法,使得位移差最大的那个区间的位移量最小。
      具体来说,假设你将Di移动到[ai+ci, bi+ci]这个位置。你希望使得maxi |ci|  最小。
    输入格式
      输入的第一行包含一个整数n,表示区间的数量。
      接下来有n行,每行2个整数ai,  bi,以一个空格分开,表示区间[ai, bi]。保证区间的长度之和至少是10000。
    输出格式
      输出一个数,表示答案。如果答案是整数,只输出整数部分。如果答案不是整数,输出时四舍五入保留一位小数。
    样例输入
    2
    10 5010
    4980 9980
    样例输出
    20
    样例说明
      第一个区间往左移动10;第二个区间往右移动20。
    样例输入
    4
    0 4000
    3000 5000
    5001 8000
    7000 10000
    样例输出
    0.5
    样例说明
      第2个区间往右移0.5;第3个区间往左移0.5即可。
    数据规模和约定
      对于30%的评测用例,1 ≤ n ≤ 10;
      对于100%的评测用例,1 ≤ n ≤ 10000,0 ≤ ai < bi  ≤ 10000。

    看到最大值最小很容易想到二分答案区间转化为判定,关键在于check函数怎么写。可以想到,需要让移动距离最大为mid的前提下把整个0~10000的区间铺满肯定是要贪心地移动,类似区间覆盖问题。不妨从左往右进行覆盖,设置一个变量pos表示从0~pos这一段已经被覆盖,需要从没有使用过的剩下的区间里选一段。假设目前在判断第i段区间,这时可以分为三种情况:s[i].l(即当前区间左端点)在pos左边,等于pos和在pos右边。处于pos两边时又需要看移动距离在mid内是否能衔接上pos,具体讨论可以看代码相关部分。

    接下来就是最麻烦的地方,我也是看了不少博客才过了这题,也不知道自己理解的对不对。一开始我直接按区间左端点sort了一遍,然后只遍历一遍结构体数组,只得了50分还是六十分来着…后来按右端点sort,再把pos初始化为0,还是只遍历一遍结构体数组,竟然改到了90分…大佬给的解释是因为是从左边开始找的,所以按右端点排序,这样移动的较少就可以覆盖的更多。我觉得可依据这么一个例子:一个区间长为m,一个为n且m>n同时n这一段包含在m里面,如果按左端点排序的话会优先考虑使用m,似乎不太划算,相当于浪费长区间了;按右端点排序的话n不能满足衔接的要求才调用m,更合理一些。其次要注意的是,肯定不能只遍历一遍结构体数组,这样会有遗漏,因此用while循环嵌套一个for循环,最终复杂度是O(n^2logn)能过掉这题。还有一点就是题目中输出的答案可能有小数可能有整数,这其实很简单,因为区间端点全都是整数,所以mid要么是整数,要么就是0.5(两个区间同时凑出1),不可能有其他的比如0.3和0.7凑(整数端点移不出来),所以直接把端点*2,0~10000改成0~20000,输出的时候/2即可。

    #include <bits/stdc++.h>
    using namespace std;
    int n;
    struct section
    {
        int l;
        int r;
    }s[10005];
    bool cmp(section a,section b)
    {
        if(a.r!=b.r)return a.r<b.r;
        else return a.l<b.l;
    }
    bool check(int mid)
    {
        int i;
        int pos=0;//pos记录当前已经填好的区间的最末端 
        bool vis[10005]={0};
        while(1)
        {
            bool find=false;
            for(i=1;i<=n;i++)
            {
                if(vis[i])continue;
                if(s[i].l>pos)//当前区间需要往左靠拢 
                {
                    if(s[i].l-pos>mid)//这一段不能满足 
                    {
                        find=false;
                    }
                    else
                    {
                        pos=s[i].r-(s[i].l-pos);
                        vis[i]=1;
                        find=true;
                    }
                }
                else if(s[i].l==pos)
                {
                    pos=s[i].r;
                    vis[i]=1;
                    find=true;
                }
                else
                {
                    if(pos-s[i].l<=mid)
                    {
                        pos=s[i].r+(pos-s[i].l);
                        vis[i]=1;
                        find=true;
                    }
                    else
                    {
                        if(s[i].r+mid>pos)
                        {
                            pos=s[i].r+mid;
                            vis[i]=1;
                        }
                        find=true;
                    }
                }
            }
            if(pos>=20000)return true;
            if(!find)break;
        }
        //这里别忘记改 
        return false;
    }
    int main()
    {
        int i;
        cin>>n;
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&s[i].l,&s[i].r);
            s[i].l*=2;
            s[i].r*=2;
        }
        sort(s+1,s+n+1,cmp);
        int left=0,right=20000,mid,ans=0;
        while(left<right)
        {
            mid=(left+right)/2;
            if(check(mid))
            {
                right=mid;
            }
            else left=mid+1;
        }
        ans=left;
        if(ans%2==0)
        {
            cout<<ans/2;
        }
        else
        {
            double aans=ans/2.0;
            printf("%.1lf",aans);
        }
    
        return 0;
    }
     
  • 相关阅读:
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    小谈抽象思维(思维篇)
    Linux工具XFTP、Xshell(centos配置java环境 工具篇 总结一)
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/12431588.html
Copyright © 2020-2023  润新知