zoukankan      html  css  js  c++  java
  • 刷题向》关于一道尺取法的神题目(BZOJ4653)(HARD-)(BZOJ 30题纪念)

      不得不说,这也许会是一道长期在我的博客里作为“HARD”难度存在的题

      这道题能很好的考验选手的思考能力,但本蒟蒻最后还是听了省队爷讲了之后才会。。。(默默面壁)

      题目里,说对于每一个点,是用当前选出的M个里面,最长长度减去最短长度作为价值。也就是说:选择长度介于最长与最短之间的边,是对答案没有影响的。(本蒟蒻并没有想到这一点。。。)

      所以由于这一点,我们可以先对于边的长度排序。

      那么题目中提到的M,是“选中多余或等于M条边”,从这里就可以看出,我们只需要选定一个头和一个尾就好,由此可以看出,这个子问题完全可以用尺取法处理。

      以尺取法不停更新最优解就好啦。

      那么怎么处理M捏,其实很简单,用离散化加线段树就可以解决关于“M个点“的子问题。

      直接甩题目&代码

      

    Description

    在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn]。现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置。换句话说,就是使得存在一个 x,使得对于每一个被选中的区间 [li,ri],都有 li≤x≤ri。
    对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度。区间 [li,ri] 的长度定义为 ri−li,即等于它的右端点的值减去左端点的值。
    求所有合法方案中最小的花费。如果不存在合法的方案,输出 −1。

    Input

    第一行包含两个正整数 n,m用空格隔开,意义如上文所述。保证 1≤m≤n
    接下来 n行,每行表示一个区间,包含用空格隔开的两个整数 li 和 ri 为该区间的左右端点。
    N<=500000,M<=200000,0≤li≤ri≤10^9

    Output

    只有一行,包含一个正整数,即最小花费。

    Sample Input

    6 3
    3 5
    1 2
    3 4
    2 2
    1 5
    1 4

    Sample Output

    2
      1 /**************************************************************
      2     Problem: 4653
      3     User: PencilWang
      4     Language: C++
      5     Result: Accepted
      6     Time:12896 ms
      7     Memory:87320 kb
      8 ****************************************************************/
      9  
     10 #include<stdio.h>
     11 #include<string.h>
     12 #include<algorithm>
     13 #include<set>
     14 using namespace std;
     15 struct shit1{int L,R,lon;}e[1010000];
     16 struct shit2{int L,R,lazy,num;}s[3030000];
     17 int fucker[1010000];
     18 int ans,n,m,k;
     19 bool cmp(shit1 a,shit1 b)
     20 {
     21     return a.lon<b.lon;
     22 }
     23 void push_down(int p)
     24 {
     25     int L=p<<1,R=p<<1|1;
     26     s[L].num+=s[p].lazy;
     27     s[L].lazy+=s[p].lazy;
     28     s[R].lazy+=s[p].lazy;
     29     s[R].num+=s[p].lazy;
     30     s[p].lazy=0;
     31     return ;
     32 }
     33 void push_up(int p)
     34 {
     35     s[p].num=max(s[p<<1].num,s[p<<1|1].num);
     36     return ;
     37 }
     38 void build(int p,int L,int R)
     39 {
     40     s[p].L=L,s[p].R=R;
     41     if(L==R)return ;
     42     int mid=(L+R)>>1;
     43     build(p<<1,L,mid);
     44     build(p<<1|1,mid+1,R);
     45     return ;
     46 }
     47 void add(int a,int b,int p,int num)
     48 {
     49     if(a<=s[p].L&&s[p].R<=b)
     50     {
     51         s[p].num+=num;
     52         s[p].lazy+=num;
     53         return ;
     54     }
     55     push_down(p);
     56     int mid=(s[p].L+s[p].R)>>1;
     57     if(a<=mid)add(a,b,p<<1,num);
     58     if(b>mid)add(a,b,p<<1|1,num);
     59     push_up(p);
     60     return ;
     61 }
     62 set<int>sb;
     63 int main()
     64 {
     65     scanf("%d%d",&n,&k);
     66     for(int i=1;i<=n;i++)
     67     {
     68     scanf("%d%d",&e[i].L,&e[i].R);
     69     sb.insert(e[i].L);sb.insert(e[i].R);
     70     e[i].lon=e[i].R-e[i].L+1;
     71     }
     72     for(set<int>::iterator p=sb.begin();p!=sb.end();++p)
     73     fucker[++m]=*p;
     74     build(1,1,m);
     75     sort(e+1,e+n+1,cmp);
     76     for(int i=1;i<=n;i++)
     77     {
     78     e[i].L=lower_bound(fucker+1,fucker+m+1,e[i].L)-fucker;
     79     e[i].R=lower_bound(fucker+1,fucker+m+1,e[i].R)-fucker;
     80     }
     81     int L=1,R=1;
     82     int Lz=e[1].lon,Rz=e[1].lon;
     83     while(e[R].lon==Rz)
     84     add(e[R].L,e[R].R,1,1),R++;
     85     R--;
     86     ans=0x3f3f3f3f;
     87     while(L<=R&&R<=n)
     88     {
     89         if(s[1].num>=k)
     90         {
     91         ans=min(ans,Rz-Lz);
     92         while(e[L].lon==Lz)
     93             add(e[L].L,e[L].R,1,-1),L++;
     94             Lz=e[L].lon;
     95         }
     96         else
     97         {
     98         Rz=e[++R].lon;
     99         while(e[R].lon==Rz&&R<=n)
    100             add(e[R].L,e[R].R,1,1),R++;
    101             if(R==n+1)break;
    102             R--;
    103         }
    104     }
    105     if(ans==0x3f3f3f3f)ans=-1;
    106     printf("%d",ans);
    107     return 0;
    108 }
  • 相关阅读:
    委托和事件
    Entity Framework应用:导航属性
    Entity Framework应用:根据实体的EntityState状态实现增删改查
    Entity Framework应用:使用EF的DataBase First模式实现数据库的增删改查
    Entity Framework应用:EntityFramework DataBase First模式
    dapper支持操作函数和事物
    单元测试
    IOC容器:Unity
    MVC教程九:异常过滤器
    MVC教程八:缓存过滤器
  • 原文地址:https://www.cnblogs.com/PencilWang/p/6003266.html
Copyright © 2011-2022 走看看