模拟赛exam

【题目描述】
你很快地完成了所有的题目,并且使准确率达到了p/q,于是开始无所事事. 老师
看见了,对你说:“你今天做的题够多的了,别再做了. 我们接下来k 天每天都要模拟,这里有很多题,你去选一些题目编k 场模拟赛吧. ”老师将所有题目都编了序号,还给你了n 种出题方案(所有方案两两不同). 每种出题方案选择所有编号属于[l; r] 的题目,作为一天的试题. 现在,你需要选出k 种出题方案(一个方案只能选取一次),分别对应k 天的模拟赛. 老师非常强调复习的重要性,因此希望有一些题目每天都出现在模拟赛当中,你需要最大化每天都出现的题目的数量.
【输入格式】
从文件exam.in 中读入数据。
输入第一行包含两个正整数n; k (1  <=k<=  n<=  3* 10^5),分别为出题方案数和模拟赛天数.接下来n 行,每行两个整数l; r (-10^9 <= l<=  r<=  109),表示一个出题方案(保证所有方案两两不同).
【输出格式】
输出到文件exam.out 中。
输出一个非负整数,表示每天都出现的题目的数量的最大值.
【样例1 输入】
4 2
1 100
40 70
120 130
125 180
【样例1 输出】
31
【样例1 解释】
选择前两种方案,编号为[40; 70] 的题目在两种方案中均出现,共有31 道题.

【样例2 输入】
3 2
1 12
15 20
25 30
【样例2 输出】
0
【样例2 解释】
所有给出的方案互不相交,所以答案为0.
【样例3】
见选手目录下的exam/exam3.in 与exam/exam3.ans。
【子任务】
对10% 的数据,k = n;
对另20% 的数据,k = 2;
对另20% 的数据,1 <= k <= n <= 20;
其余5 组数据,n = 10^2; 10^3; 10^4; 10^5; 3 * 10^5.

因为要从n种方案里选出k个,所以不妨把每个区间先按左端点排序,选出前k-1个,同时维护一个越小的整数优先级越高的单调队列,把它们的右端点存进去。然后看第k个区间,如果它的左端点小于前k-1个区间最小的右端点,它就是合法的。这时还需要将它的右端点和前k-1个区间最小的右端点(以下称为当前最小右端点)比较,如果它的右端点小于当前最小右端点,则它是被包含的,题目数量就是它自己的左右端点相减+1;否则,用当前最小右端点与它的左端点相减+1得到sum。然后将当前最小右端点出队,将现在第k个区间的右端点入队,以此类推。那么如果第k个区间的左端点大于当前最小右端点,则现在的状态无法满足某道题被选了k次,这时就要不断将队首元素出队,将第k个区间右端点入队,直到达到合法的状态。

代码如下

 1 #include<cstdio>
 2 #include<algorithm> 
 3 #include<queue>
 4 using namespace std;
 5 #define ll long long int
 6 int k,n;
 7 ll sum,ans;
 8 struct node
 9 {
10     ll l,r;
11 }t[300005];
12 ll cmp(node a,node b)
13 {
14     return a.l < b.l;//按左端点排序 
15 }
16 priority_queue<ll,vector<ll>,greater<ll> > pq;//越小的整数优先级越高 
17 int main()
18 {
19     scanf("%d%d",&n,&k);
20     for(int i = 1;i <= n;i++){
21         scanf("%lld%lld",&t[i].l,&t[i].r);
22     }
23     sort(t+1,t+n+1,cmp);
24     for(int i = 1;i < k;i++)
25     {
26         pq.push(t[i].r);//优先队列中存右端点 
27     }
28     for(int i = k;i <= n;i++)
29     {
30         if(t[i].l <= pq.top())
31         {
32             if(t[i].r > pq.top())
33             {
34                 sum = pq.top() - t[i].l + 1;
35                 pq.pop();
36                 pq.push(t[i].r);
37             }
38             else
39             {
40                 sum = t[i].r - t[i].l + 1;
41             }
42             ans = max(ans,sum);    
43         }
44         else
45         {
46             pq.pop();
47             pq.push(t[i].r);
48         }
49     }
50     printf("%lld",ans);
51     return 0;
52 }

猜你喜欢

转载自www.cnblogs.com/peppa/p/9443481.html