[SCOI2009]生日禮物

如有錯誤,請留言提醒,不要坑到小朋友

小西有一條很長的綵帶,綵帶上掛着各式各樣的彩珠。已知彩珠有N個,分爲K種。簡單的說,可以將綵帶考慮爲x軸,每一個彩珠有一個對應的座標(即位置)。某些座標上可以沒有彩珠,但多個彩珠也可以出現在同一個位置上。小布生日快到了,於是小西打算剪一段綵帶送給小布。爲了讓禮物綵帶足夠漂亮,小西希望這一段綵帶中能包含所有種類的彩珠。同時,爲了方便,小西希望這段綵帶儘可能短,你能幫助小西計算這個最短的長度麼?綵帶的長度即爲綵帶開始位置到結束位置的位置差。

Input

6 3 
1 5 
2 1 7 
3 1 3 8 

Output

3


我們用小根堆來維護綵帶的左端點,右端點就是堆中元素的最大值。由於題目給出的每一種小球的座標單調遞增,所以很好求出每個球最近的下一個同類球是哪個。題目要求所有小球都必須在綵帶上,就是說堆內的元素必須爲K個,所以我們先將每種球的座標最小的放進堆裏,並且記錄初始答案,然後每次刪除堆頂,爲了維持堆裏的元素個數,所以我們還要插入一個與刪除元素相同種類的下一個球,就可更新答案了,當沒有同種球可以插入時,就可以結束了。

在這裏有人會有疑惑了,爲什麼這種球沒了,不能改變其他的球來更新答案呢? 原因很簡單,因爲,插入其他的球,並不會改變堆頂,也就是說不會改變最小值,而只可能會讓最大值變大,所以不可能在得到最優解。

還有人有疑惑,堆中元素的最大值怎麼求呢? 其實,最大值就是所有進入過堆的元素的最大值,因爲我們每次只將最小值刪除,而不影響最大值,最大值是不斷變大的。

總的時間複雜度爲:O(NlogN),足以在一秒的時間內解決了。

#include<cstdlib>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#define maxn 61  
#define maxp 1000010
#define maxx 1000010
using namespace std;
typedef pair<int,int> PII;
inline int read(){
	int tmp=0;char ch;
	while(ch=getchar())if('0'<=ch&&ch<='9')break;
	for(;'0'<=ch&&ch<='9';ch=getchar())tmp=tmp*10+ch-'0';
	return tmp;
}
PII aa[maxx];
int tot,f[maxn],sum,n,k,ans=0x7fffffff;
priority_queue<PII,vector<PII>,greater<PII> >q;
int main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=k;i++){
		int t=read();
		for(int j=1;j<=t;j++){
			int b=read();
			aa[tot+j]=make_pair(b,i);
		}
		tot+=t;
	}
//	printf("%d\n",tot);
	sort(aa+1,aa+tot+1);
	for(int i=1;i<=tot;i++){
		q.push(aa[i]);
		if(!f[aa[i].second])sum++;
		f[aa[i].second]=aa[i].first;
		while(f[q.top().second]!=q.top().first)q.pop();
		if(sum==k){ans=min(ans,aa[i].first-q.top().first);}
	//	printf("%d %d %d %d %d\n",ans,aa[i].first,aa[i].second,q.top().first,q.top().second);
	}
	printf("%d\n",ans);
//	system("pause");
}


var
 h,fir,e:array[0..60] of longint;
 next,num,data:array[0..1000000] of longint;
 n,k,tot,i,j,len,sum,a,ans,max:longint;

 procedure ins(x,xx:longint);
 var now,fa,t:longint;
 begin
   inc(len);
   h[len]:=x;
   e[len]:=xx;
   now:=len;
   fa:=now div 2;
   while now>1 do
   begin
     if h[now]<h[fa] then
     begin
      t:=h[now]; h[now]:=h[fa]; h[fa]:=t;
      t:=e[now]; e[now]:=e[fa]; e[fa]:=t;
      now:=fa; fa:=fa div 2;
     end
     else
     break;
   end;
 end;

 procedure del;
 var now,son,t:longint;
 begin
   h[1]:=h[len];
   e[1]:=e[len];
   dec(len);
   now:=1;
   while now<=len do
   begin
     if h[now*2]<h[now*2+1] then
        son:=now*2
        else
        son:=now*2+1;

     if (son<=len) and (h[now]>h[son]) then
     begin
       t:=h[now]; h[now]:=h[son]; h[son]:=t;
       t:=e[now]; e[now]:=e[son]; e[son]:=t;
       now:=son;
     end
     else
     break;
   end;
 end;

begin
  readln(n,k); tot:=0; len:=0; max:=0;
  for i:=1 to k do
  begin
   read(sum);
   inc(tot); read(data[tot]); fir[i]:=tot;
   for j:=2 to sum do
   begin
    inc(tot); read(data[tot]);
    next[tot-1]:=tot;
   end;
  end;
  for i:=1 to k do
  begin
    ins(data[fir[i]],fir[i]);
    if  max<data[fir[i]] then
    max:=data[fir[i]];
  end;
  ans:=max-h[1];
  while true do
  begin
    if next[e[1]]=0 then break;
    a:=e[1]; del; ins(data[next[a]],next[a]);
    if max<data[next[a]] then max:=data[next[a]];
    if ans>max-h[1] then
     ans:=max-h[1];
  end;
  writeln(ans);
end.



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章