本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

Description

Siruseri政府建造了一座新的会议中心。许多公司对租 借会议中心的会堂很感兴趣,他们希望能够在里面举行会议。 对于一个客户而言,仅当在开会时能够独自占用整个会堂,他才会租借会堂。会议中心的销售主管认为:最好的策略应该是将会堂租借给尽可能多的客户。显然,有 可能存在不止一种满足要求的策略。 例如下面的例子。总共有4个公司。他们对租借会堂发出了请求,并提出了他们所需占用会堂的起止日期(如下表所示)。 开始日期 结束日期 公司1 4 9 公司2 9 11 公司3 13 19 公司4 10 17 上例中,最多将会堂租借给两家公司。租借策略分别是租给公司1和公司3,或是公司2和公司3,也可以是公司1和公司4。注意会议中心一天最多租借给一个公 司,所以公司1和公司2不能同时租借会议中心,因为他们在第九天重合了。 销售主管为了公平起见,决定按照如下的程序来确定选择何种租借策略:首先,将租借给客户数量最多的策略作为候选,将所有的公司按照他们发出请求的顺序编 号。对于候选策略,将策略中的每家公司的编号按升序排列。最后,选出其中字典序最小1的候选策略作为最终的策略。 例中,会堂最终将被租借给公司1和公司3:3个候选策略是{(1,3),(2,3),(1,4)}。而在字典序中(1,3)<(1,4)< (2,3)。 你的任务是帮助销售主管确定应该将会堂租借给哪些公司。

Input

输入的第一行有一个整数N,表示发出租借会堂申请的公司的个数。第2到第N+1行每行有2个整数。第i+1行的整数表示第i家公司申请租借的起始和终止日期。对于每个公司的申请,起始日期为不小于1的整数,终止日期为不大于10^9的整数。N≤200000

Output

输出的第一行应有一个整数M,表示最多可以租借给多少家公司。第二行应列出M个数,表示最终将会堂租借给哪些公司。

Sample Input

4
4 9
9 11
13 19
10 17

Sample Output

2
1 3

正解:倍增+贪心

解题报告:  

   题目要求从若干个闭区间中取出尽可能多的区间,并且保证方案的字典序最小。

   在只有第一问的情况下,这就是一道贪心的经典模型了。但是我们考虑如何保证我们选出来的方案字典序最小。显然我们可以发现一个问题,如果我们从第一个区间开始考虑,假设把它选了,没有使总数量减少,那么我们肯定可以选择它(通过字典序最小的原则很容易想通)。那么我们的任务就是如何快速的检查是否不会使得总数量减少,所以我们需要做的就是快速查询区间的最大放的数量(通过预处理实现)。

  假设get_ans函数可以快速查询区间的最大放的数量,那么如果我想放入一个[l0,r0]的区间,那么需要满足get_ans(l,r)=get_ans(l,l0-1)+get_ans(r0+1,r)+1,这个式子很容易想通。l是离l0最近的上次插入的区间的右端点,r是离r0最近的上次插入的左端点。开始我还在想怎么维护选择区间之后,这个区间的数量变化情况,事实上我们并不关心怎么变,我们只知道它不会使得数量变化即可。也就是说,我只要知道我能影响的区间怎么变,外面的区间因为没有修改,所以肯定也不会变化,换而言之当前影响区间不变则整个区间的总数量就不会变。

   那么我们需要预处理什么呢?首先我们需要在log n的时间内实现快速查询给定范围最大可以选取的区间数量。那么我们把区间重新排序,并且去掉互相包含的区间中较大的部分(显然可以知道这是可行的),这可以先按左端点排序,再用一个右端点单调递增的栈实现。之后对于每个保留下来的区间i,考虑用f[i][j]表示从第i个区间开始往后连续选取2^j个区间之后落在哪个区间上。这个预处理也很简单,n log n。这其实用的就是一个倍增的思想。所以对于每一次查询[l,r],我可以找到[l,r]中的第一个区间,然后倍增的找区间,不断地往后跳并累加答案。通过上述操作可以实现查询操作。

   另外,我们选取了一个区间之后可以用一个set维护一下我选取的区间的端点坐标,方便我快速查询最近的坐标。

   整个题目细节比较多,实现起来稍显复杂,需要一点时间。

  1. //It is made by ljh2000
  2. #include <iostream>
  3. #include <cstdlib>
  4. #include <cstring>
  5. #include <cstdio>
  6. #include <cmath>
  7. #include <algorithm>
  8. #include <ctime>
  9. #include <vector>
  10. #include <queue>
  11. #include <map>
  12. #include <set>
  13. using namespace std;
  14. typedef long long LL;
  15. const int inf = (<<);
  16. const int MAXN = ;
  17. int n,cnt,end,ans;
  18. int L[MAXN],nn;
  19. bool pd[MAXN];
  20. int f[MAXN][];//f[i][j]表示第i个区间往后取2^j个可行的区间后的可以取到第几个区间
  21. struct node{
  22. int l,r;
  23. }a[MAXN],b[MAXN];
  24. set<int>S;
  25. inline bool cmpl(node q,node qq){ if(q.l==qq.l) return q.r>qq.r; return q.l<qq.l; }
  26. inline int getint()
  27. {
  28. int w=,q=; char c=getchar();
  29. while((c<'' || c>'') && c!='-') c=getchar(); if(c=='-') q=,c=getchar();
  30. while (c>='' && c<='') w=w*+c-'', c=getchar(); return q ? -w : w;
  31. }
  32.  
  33. inline void build(){
  34. for(int i=;i<=n;i++) b[i]=a[i]; sort(b+,b+n+,cmpl);
  35. cnt=; b[++cnt]=b[];
  36. for(int i=;i<=n;i++) {
  37. while(b[i].r<=b[cnt].r && cnt>) cnt--;
  38. b[++cnt]=b[i];
  39. }
  40. nn=; for(int i=;i<=cnt;i++) L[++nn]=b[i].l;
  41. L[++nn]=inf; int xia; for(int i=;i<=;i++) f[cnt+][i]=cnt+;
  42. for(int i=;i<=cnt;i++) { xia=upper_bound(L+,L+nn+,b[i].r)-L; f[i][]=xia; }
  43. for(int j=;j<=;j++) for(int i=;i<=cnt;i++) if(f[i][j-] && f[f[i][j-]][j-]) f[i][j]=f[f[i][j-]][j-];
  44. }
  45.  
  46. inline int get_ans(int l,int r){//得到区间[l,r]的可选区间的个数
  47. if(l>r) return ; if(l>end) return ;//!!!
  48. int daan=,head,cc; head=lower_bound(L+,L+nn+,l)-L;
  49. if(head>cnt) return ;//!!!
  50. if(b[head].r>r) return ;
  51. for(int i=;i>=;i--) {
  52. if(f[head][i]==cnt+) continue; if(f[head][i]==) continue;
  53. cc=b[f[head][i]].r; if(cc>r) continue;
  54. head=f[head][i]; daan+=(<<i);
  55. }
  56. return daan;
  57. }
  58.  
  59. inline void work(){
  60. n=getint(); for(int i=;i<=n;i++) a[i].l=getint(),a[i].r=getint(),L[++cnt]=a[i].l,L[++cnt]=a[i].r;
  61. sort(L+,L+cnt+); end=nn=unique(L+,L+cnt+)-L-;
  62. for(int i=;i<=n;i++) a[i].l=lower_bound(L+,L+nn+,a[i].l)-L,a[i].r=lower_bound(L+,L+nn+,a[i].r)-L;
  63. build(); int now,nowl,nowr; ans=get_ans(,end); printf("%d\n",ans);
  64. S.insert(-inf); S.insert(inf); bool flag=false;
  65. for(int i=;i<=n;i++) {
  66. now=*S.lower_bound(a[i].l);
  67. if(now==inf || !pd[now]) {
  68. if(now<=a[i].r) continue;
  69. nowl=*--S.lower_bound(a[i].l); nowl++;
  70. nowr=*S.lower_bound(a[i].r); nowr--;
  71. now=get_ans(nowl,a[i].l-)+get_ans(a[i].r+,nowr)+;
  72. if(now<get_ans(nowl,nowr)) continue;
  73. S.insert(a[i].l); S.insert(a[i].r); if(a[i].l!=a[i].r) pd[a[i].r]=;//!!!
  74. if(flag) printf(" "); printf("%d",i); flag=true;
  75. }
  76. }
  77. }
  78.  
  79. int main()
  80. {
  81. work();
  82. return ;
  83. }

BZOJ1178 [Apio2009]CONVENTION会议中心的更多相关文章

  1. bzoj1178 [Apio2009]CONVENTION会议中心 区间dp+贪心

    [Apio2009]CONVENTION会议中心 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 1130  Solved: 444[Submit][S ...

  2. BZOJ1178 [Apio2009]CONVENTION会议中心 贪心 set

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1178 题意概括 一堆线段,现在取出最多条数,使其互不覆盖,并输出字典序最小的方案. 题解 这题好坑 ...

  3. 【BZOJ-1178】CONVENTION会议中心 倍增 + set (神思路好题!)

    1178: [Apio2009]CONVENTION会议中心 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 812  Solved: 323[Subm ...

  4. 1178: [Apio2009]CONVENTION会议中心

    1178: [Apio2009]CONVENTION会议中心 https://lydsy.com/JudgeOnline/problem.php?id=1178 分析: set+倍增. 首先把所有有包 ...

  5. 【bzoj1178】 Apio2009—CONVENTION会议中心

    http://www.lydsy.com/JudgeOnline/problem.php?id=1178 (题目链接) 题意 给出n个区间,问在区间两两不相交的情况下最多能选出多少区间,并输出字典序最 ...

  6. bzoj 1178 [Apio2009]CONVENTION会议中心

    这题好难啊! 我好菜啊! 思路:对于最多线段不相交, 我们可以按左端点sort之后,贪心取. 但是这个题要求选取的线段排序之后序号的字典序最小. 那么我们如果按序号贪心地从大往小往里放, 那么对于第k ...

  7. bzoj 1178: [Apio2009]CONVENTION会议中心(少见做法掉落!)【贪心+二分】

    数组若干+手动二分一个的算法,bzoj rank8 ===============================废话分割线=================================== 我我 ...

  8. 【BZOJ】【1178】【APIO2009】convention会议中心

    贪心 如果不考虑字典序的话,直接按右端点排序,能选就选,就可以算出ans…… 但是要算一个字典序最小的解就比较蛋疼了= = Orz了zyf的题解 就是按字典序从小到大依次枚举,在不改变答案的情况下,能 ...

  9. 【BZOJ 1178】【APIO 2009】CONVENTION会议中心

    http://www.lydsy.com/JudgeOnline/problem.php?id=1178 这道题想了好久没想明白,倍增数组通过看题解很快就明白了,但是一小段区间内应有的最多线段数一直不 ...

随机推荐

  1. iOS APNS配置(转)

    Introduction To send Push notification to an application/device couple you need an unique device tok ...

  2. lecture14-RBM的堆叠、修改以及DBN的决策学习和微调

    这是Hinton的第14课,主要介绍了RBM和DBN的东西,这一课的课外读物有三篇论文<Self-taught learning- transfer learning from unlabele ...

  3. favicon.ico文件简介

    本地调试时,控制台经常会打印如下的错误(对 favicon.ico 的请求在 chrome 调试面板下不可见,可在抓包工具,比如 Fiddler 中看到): favicon.ico 是啥?看下面这张图 ...

  4. bootstrap-datepicker带中文的js文件

    ) { $(".datepicker").datepicker({ language: "zh-CN", autoclose: true,//选中之后自动隐藏日 ...

  5. idea 生成代码中带参数final修饰

  6. 几张图弄明白ios布局中的尺寸问题

    背景 先说说逆向那事.各种曲折..各种技术过时,老老实实在啃看雪的帖子..更新会有的. 回正题,这里讨论的是在Masnory框架下的布局问题.像我这种游击队没师傅带,什么都得自己琢磨,一直没闹明白下面 ...

  7. 学习SQLite之路(四)

    20160621 更新 参考: http://www.runoob.com/sqlite/sqlite-tutorial.html 1. SQLite   alter命令:不通过执行一个完整的转储和数 ...

  8. NodeJs爬虫—“眼睛好看是一种什么样的体验?”

    逛知乎的时候经常看见有好多的福利贴(钓鱼贴),这不最近又让我发现了一个——眼睛好看是一种什么样的体验是一种怎么样的体验呢?我决定把答案里的照片都下到我的电脑里好好体验一下,怎么做呢,一张一张下好麻烦, ...

  9. 让计算机崩溃的python代码,求共同分析

    在现在的异常机制处理的比较完善的编码系统里面,让计算机完全崩溃无法操作的代码还是不多的.今天就无意运行到这段python代码,运行完,计算机直接崩溃,任务管理器都无法调用,任何键都用不了,只能强行电源 ...

  10. bootstrap点滴

    1.nav-stacked 这个属性可以决定 tab的变为竖的,不添加的话为横向的. 2.tab  横向的 ul中必须含有nav nav-tabs ul li a 中必须有data-toggle=&q ...