1. 程式人生 > >D. Fedor and coupons(貪心+優先佇列)

D. Fedor and coupons(貪心+優先佇列)

Note

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張優惠券     每張優惠券可以可以優惠liri 區間中的商品     現在選擇k張優惠

券     問能優惠k次的商品最多有多少個   怎麼選擇優惠券

分析:

題目的本質意思是    從n個區間中任意選取k個區間使重疊區域為k次    求出k次重疊區域的最大值     並輸出所選區域的編號   分析後可發現     選取的k個區域 k次重疊區間大小 == 右端點最小值 - 左端點最大值 + 1    若所選k個區間重疊次數不為k次   得出區間大小為負數  符合題目要求   所以   按左端點將區間降序排列    用優先佇列維護一個k值為區間個數  便可解決

AC程式碼:

[cpp] view plain copy print?
  1. #include <stdio.h>
  2. #include <queue>
  3. #include <string.h>
  4. #include <algorithm>
  5. typedeflonglong ll;  
  6. usingnamespace std;  
  7. struct node{  
  8.     ll l;  
  9.     ll r;   
  10.     ll index;  
  11. }a[300005];  
  12. int cmp(node x,node y){  
  13.     if (x.l==y.l)  
  14.     return
     x.r<y.r;  
  15.     return x.l<y.l;  
  16. }  
  17. struct cmp2{  
  18.     bool operator()(ll x,ll y)  
  19.     {  
  20.         return x > y;  
  21.     }  
  22. };  
  23. int main (){  
  24.     int n,k;  
  25.     while (scanf("%d%d",&n,&k)!=EOF){  
  26.         memset(a,0,sizeof(a));  
  27.         for (int i=0;i<n;i++){  
  28.             scanf ("%lld%lld",&a[i].l,&a[i].r);  
  29.             a[i].index=i+1;  
  30.         }  
  31.         sort(a,a+n,cmp);  
  32.         priority_queue<ll,vector<ll>,cmp2> Q;  
  33.         ll left=0;   
  34.         ll right=0;  
  35.         ll len=0;  
  36.         ll ans=-1;  
  37.         for (int i=0;i<n;i++){  
  38.             Q.push(a[i].r);  
  39.             if (Q.size()>k)  
  40.                 Q.pop();  
  41.             if (Q.size()==k){//    求最大重疊區域    記錄左端點   
  42.                 len=Q.top()-a[i].l+1;//   左端點最大值減去右端點最小值+1 == 區間長度 
  43.                 //printf ("%lld####\n",len);
  44.             }  
  45.             if(ans<len){  
  46.                 ans=len;  
  47.                 //記住最大左端點和最小右端點 
  48.                 left=a[i].l;  
  49.                 right=Q.top();  
  50.             }   
  51.         }  
  52.         printf ("%lld\n",ans);  
  53.         if (!ans){// 區間大小為0  任意選取k個區間      
  54.             printf ("1");  
  55.             for (int i=2;i<=k;i++)  
  56.             printf (" %d",i);  
  57.             continue;  
  58.         }   
  59.         for (int i=0;i<n&&k>0;i++){//       輸出區間 
  60.             if (a[i].r>=right&&a[i].l<=left){  
  61.                 printf ("%d ",a[i].index);  
  62.                 k--;  
  63.             }  
  64.         }  
  65.         putchar('\n');  
  66.     }  
  67.     return 0;  
  68. }  
#include <stdio.h>
#include <queue>
#include <string.h>
#include <algorithm>
typedef long long ll;
using namespace std;

struct node{
	ll l;
	ll r; 
	ll index;
}a[300005];
int cmp(node x,node y){
	if (x.l==y.l)
	return x.r<y.r;
	return x.l<y.l;
}
struct cmp2{
	
	bool operator()(ll x,ll y)
	{
		return x > y;
	}
};
int main (){
	int n,k;
	while (scanf("%d%d",&n,&k)!=EOF){
		memset(a,0,sizeof(a));
		for (int i=0;i<n;i++){
			scanf ("%lld%lld",&a[i].l,&a[i].r);
			a[i].index=i+1;
		}
		sort(a,a+n,cmp);
		priority_queue<ll,vector<ll>,cmp2> Q;
		ll left=0; 
		ll right=0;
		ll len=0;
		ll ans=-1;
		for (int i=0;i<n;i++){
			Q.push(a[i].r);
			if (Q.size()>k)
				Q.pop();
		
			if (Q.size()==k){//    求最大重疊區域    記錄左端點   
				len=Q.top()-a[i].l+1;//   左端點最大值減去右端點最小值+1 == 區間長度 
				//printf ("%lld####\n",len);
			}
			if(ans<len){
				ans=len;
				//記住最大左端點和最小右端點 
				left=a[i].l;
				right=Q.top();
			} 
		}
		
		printf ("%lld\n",ans);
		if (!ans){// 區間大小為0  任意選取k個區間      
			printf ("1");
			for (int i=2;i<=k;i++)
			printf (" %d",i);
			continue;
		} 
		for (int i=0;i<n&&k>0;i++){//       輸出區間 
			if (a[i].r>=right&&a[i].l<=left){
				printf ("%d ",a[i].index);
				k--;
			}
		}
		putchar('\n');
	}
	return 0;
}