bzoj 1293 生日礼物

 

小西有一条很长的彩带,彩带上挂着各式各样的彩珠。已知彩珠有N个,分为K种。简单的说,可以将彩带考虑为x轴,每一个彩珠有一个对应的坐标(即位置)。某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上。 小布生日快到了,于是小西打算剪一段彩带送给小布。为了让礼物彩带足够漂亮,小西希望这一段彩带中能包含所有种类的彩珠。同时,为了方便,小西希望这段彩带尽可能短,你能帮助小西计算这个最短的长度么?彩带的长度即为彩带开始位置到结束位置的位置差。Input第一行包含两个整数N, K,分别表示彩珠的总数以及种类数。接下来K行,每行第一个数为Ti,表示第i种彩珠的数目。接下来按升序给出Ti个非负整数,为这Ti个彩珠分别出现的位置。Output应包含一行,为最短彩带长度。Sample Input6 3
1 5
2 1 7
3 1 3 8

Sample Output3

庆祝一下,这道题拖了一周了,其实只是一个非常简单的队列模拟,那时候直接想复杂了,首先,我们从最左边开始,找到满足“k”种的第一个位置,把他作为队列的tail,我们中间会做一个哈希,表示每个珠子的数量,写一个howmany表示珠子的种类数,然后找到tail之后,从左边开始寻找最远的一个head,如此反复下去,就成功了

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
struct pt{
	int pos,value;
};
pt a[1000003];
int ts[69];
int ans=2147483647;
int cnt,n,k;
bool cmp(pt m,pt n)
{
	return m.pos<n.pos;
}
int main()
{
	cin>>n>>k;
	for(int i=0;i<k;i++)
	{
		int x;
		scanf("%d",&x);
		for(int j=0;j<x;j++)
		{
			int tmp;
			scanf("%d",&tmp);
			a[cnt]=(pt){tmp,i};
			cnt++;
		}
	}
	sort(a,a+cnt,cmp);
	int l=0,r=0;
	int howmany=0;
	while(true)
	{		
	    if(r>=n)
		break;
		while(howmany<k&&r<n)
		{
			    if(ts[a[r].value]==0)
			    howmany++;
				ts[a[r].value]++;
				r++;
		}	
		while(true)
		{   
			l++;
			ts[a[l-1].value]--;
			if(ts[a[l-1].value]==0)
			{
				int v=a[r-1].pos-a[l-1].pos;
				if(v<ans)
				{
					ans=v;
				}
				howmany--;
				break;
			}
		}

	}
	cout<<ans<<endl;
}

  

posted @ 2019-07-06 15:43  coolwx  阅读(154)  评论(0编辑  收藏  举报