首页 > 代码库 > codeforces754D Fedor and coupons
codeforces754D Fedor and coupons
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!
Description
All our characters have hobbies. The same is true for Fedor. He enjoys shopping in the neighboring supermarket.
The goods in the supermarket have unique integer ids. Also, for every integer there is a product with id equal to this integer. Fedor has ndiscount coupons, the i-th of them can be used with products with ids ranging from li to ri, inclusive. Today Fedor wants to take exactly kcoupons with him.
Fedor wants to choose the k coupons in such a way that the number of such products x that all coupons can be used with this product x is as large as possible (for better understanding, see examples). Fedor wants to save his time as well, so he asks you to choose coupons for him. Help Fedor!
The first line contains two integers n and k (1?≤?k?≤?n?≤?3·105) — the number of coupons Fedor has, and the number of coupons he wants to choose.
Each of the next n lines contains two integers li and ri (?-?109?≤?li?≤?ri?≤?109) — the description of the i-th coupon. The coupons can be equal.
In the first line print single integer — the maximum number of products with which all the chosen coupons can be used. The products with which at least one coupon cannot be used shouldn‘t be counted.
In the second line print k distinct integers p1,?p2,?...,?pk (1?≤?pi?≤?n) — the ids of the coupons which Fedor should choose.
If there are multiple answers, print any of them.
4 2
1 100
40 70
120 130
125 180
31
1 2
3 2
1 12
15 20
25 30
0
1 2
5 2
1 10
5 15
14 50
30 70
99 100
21
3 4
In the first example if we take the first two coupons then all the products with ids in range [40,?70] can be bought with both coupons. There are 31 products in total.
In the second example, no product can be bought with two coupons, that is why the answer is 0. Fedor can choose any two coupons in this example.
正解:堆+贪心
解题报告:
这道题概括出来的模型十分简洁经典:从n条线段中取出恰好k条使得交集长度尽可能长,输出最优值和方案。
我开始想了很久的单调性,但是并不能实现单调决策,更不能还原历史版本。所以我就想了想,似乎带个log就很可做了?
考虑先按左端点排序,维护一个右端点坐标的小根堆,那么很容易发现我只需要保证堆的大小始终小于等于k即可。当我每次扫到一个左端点时,将其右端点与堆顶作比较,如果比堆顶小则不作考虑,否则,删除堆顶,把这个新的右端点坐标加入堆中。每次只需用堆顶减去当前处理的线段的左端点来更新答案(当且仅当堆中恰好有k个元素)。输出方案的话,用同样方法再做一次即可。
//It is made by ljh2000 #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <ctime> #include <vector> #include <queue> #include <map> #include <set> #include <string> using namespace std; typedef long long LL; const int MAXN = 300011; int n,k,ans,dui[MAXN]; struct node{int pos,id; inline bool operator < (const node &a)const{ return a.pos<pos; } }tmp; priority_queue<node>Q; struct seq{int l,r,id;}a[MAXN]; inline bool cmp(seq q,seq qq){ return q.l<qq.l; } inline int getint(){ int w=0,q=0; char c=getchar(); while((c<‘0‘||c>‘9‘) && c!=‘-‘) c=getchar(); if(c==‘-‘) q=1,c=getchar(); while (c>=‘0‘&&c<=‘9‘) w=w*10+c-‘0‘,c=getchar(); return q?-w:w; } inline void work(){ n=getint(); k=getint(); for(int i=1;i<=n;i++) a[i].l=getint(),a[i].r=getint(),a[i].id=i; sort(a+1,a+n+1,cmp); ans=-1;//!!! for(int i=1;i<=n;i++) { if(!Q.empty())tmp=Q.top(); if((int)Q.size()<k) { tmp.pos=a[i].r; tmp.id=i; Q.push(tmp); } else { if(a[i].r>tmp.pos) { Q.pop(); tmp.pos=a[i].r; tmp.id=i; Q.push(tmp); } } if((int)Q.size()>=k) ans=max(Q.top().pos-a[i].l,ans); } printf("%d\n",ans+1); if(ans==-1) { for(int i=1;i<=k;i++) printf("%d ",i); return ; } int lans=ans; ans=-1; while(!Q.empty()) Q.pop(); for(int i=1;i<=n;i++) { if(!Q.empty()) tmp=Q.top(); if((int)Q.size()<k) { tmp.pos=a[i].r; tmp.id=a[i].id;//!!! Q.push(tmp); } else { if(a[i].r>tmp.pos) { Q.pop(); tmp.pos=a[i].r; tmp.id=a[i].id;//!!! Q.push(tmp); } } if((int)Q.size()>=k) { ans=max(Q.top().pos-a[i].l,ans); if(ans==lans) { int cnt=0; while(!Q.empty()) { tmp=Q.top(); dui[++cnt]=tmp.id; Q.pop(); } sort(dui+1,dui+k+1); for(int i=1;i<=k;i++) printf("%d ",dui[i]); return ; } } } } int main() { work(); return 0; }
codeforces754D Fedor and coupons