1. 程式人生 > >【BZOJ- 1293】生日禮物 (尺取法)

【BZOJ- 1293】生日禮物 (尺取法)

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

Input

第一行包含兩個整數N, K,分別表示彩珠的總數以及種類數。接下來K行,每行第一個數為Ti,表示第i種彩珠的數目。接下來按升序給出Ti個非負整數,為這Ti個彩珠分別出現的位置。

Output

應包含一行,為最短綵帶長度。

Sample Input

6 3 1 5 2 1 7 3 1 3 8

Sample Output

3

Hint

有多種方案可選,其中比較短的是1~5和5~8。後者長度為3最短。
【資料規模】
對於50%的資料, N≤10000;
對於80%的資料, N≤800000;
對於100%的資料,1≤N≤1000000,1≤K≤60,0≤彩珠位置<2^31。

思路:

很明顯的尺取,開始終點移動走過一個點就把這個點上的所有珠寶都加入佇列,當珠寶種類大於k時,起點移動,讓珠寶出佇列。不過要注意當一個點上的珠寶種類的數量正好為k是,其長度為1。從這道題也學到了pair和優先佇列的結合使用,記一下。

ac程式碼:

#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring> 
#include<queue>
#include<stack> 
#include<string.h>
#include<set>
#define ll long long
#define PI acos(-1.0)
#define eps 1e-8
using namespace std;
typedef pair<int,int> pii;
pair<int,int> p1;
map<int,int> mp;
struct cmp{
    bool operator() (const pii p1,const pii p2){
        return p1.first > p2.first;         /// first 小的先彈出
    }
};
int main()
{
	/*
	這裡不用優先佇列也可以,將資訊存在一個結構體陣列中,按照位置排一下序,然後掃一遍,掃到一個往後看看有沒有位置和這個相同的,有就都加進來。
	或者用二維的vector,掃到一個點,把這一點對應的這一列都加入,求這一列的長度時,先定義一個變數接收size,否則在迴圈中寫size()的話時間複雜度是O(n) 
	*/
    //priority_queue<pair<int,int>,vector<pii>,greater<pii> > que,q2;
    //也可以用上面的寫法
	priority_queue<pair<int,int>,vector<pii>,cmp> que,q2;
	int len=0x3f3f3f3f;
	int n,k;
	scanf("%d%d",&n,&k);
	int num=0;
	for(int i=1;i<=k;i++)
	{
		p1.second=i;
		int t; 
		scanf("%d",&t);
		for(int j=0;j<t;j++)
		{
			int wi;
			scanf("%d",&wi);
			p1.first=wi;
			que.push(p1); 
		}
	} 
	int st=que.top().first;
	int ed=que.top().first;
	while(!(que.empty()&&q2.empty()))
	{
		while(num<k&&!que.empty())
		{
			p1=que.top();
			que.pop();
			ed=p1.first;
			if(mp[p1.second]==0)
			num++;
			mp[p1.second]++;
			q2.push(p1);
			
			while(!que.empty()&&que.top().first==p1.first)
			{
				pair<int,int> p2;
				p2=que.top();
				que.pop();
				if(mp[p2.second]==0)
				num++;
				mp[p2.second]++;
				
				q2.push(p2);
			}
		}
		while(num==k&&!q2.empty())
		{
			int tt=ed-st;
			if(st==ed)
			tt=1;
			len=min(len,tt);
			p1=q2.top();
			q2.pop();
			mp[p1.second]--;
			if(mp[p1.second]==0)
			num--;
			while(!q2.empty()&&q2.top().first==p1.first)
			{
				pair<int,int> p2;
				p2=q2.top();
				q2.pop();
				mp[p2.second]--;
				if(mp[p2.second]==0)
				num--;
			}
			st=q2.top().first;
		}
		if(num<k&&que.empty())
		break;
	}
	printf("%d\n",len);
	return 0;
}