BZOJ1293 [SCOI2009]生日礼物 离散化

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ1293


题意概括

  彩珠有N个,分为K种。每一个彩珠有一个对应的坐标。坐标上可以没有彩珠,多个彩珠也可以出现在同一个位置上。小西希望一段彩带中能包含所有种类的彩珠。帮助小西计算这段彩带这个最短的长度。彩带的长度即为彩带开始位置到结束位置的位置差。


 

题解

  水题。

  对于读入的,先离散化一下。

  然后L和R卡过去就可以了。直接看代码应该就懂了吧?

  如果不懂,建议去做做NOIP2016普及组T3。


 

代码

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <vector>
using namespace std;
const int N=1000000+5,M=60+5;
int n,m,Hash[N],hs,tot[M];
vector <int> a[M],tre[N];
void Get_Hash(){
	sort(Hash+1,Hash+hs+1);
	int hs_=1;
	for (int i=2;i<=hs;i++)
		if (Hash[i]!=Hash[i-1])
			Hash[++hs_]=Hash[i];
	hs=hs_;
}
int find(int x){
	int le=1,ri=hs,mid;
	while (le<=ri){
		mid=(le+ri)>>1;
		if (Hash[mid]==x)
			return mid;
		if (Hash[mid]<x)
			le=mid+1;
		else
			ri=mid-1;
	}
	return -1;
}
int main(){
	scanf("%d%d",&n,&m);
	hs=0;
	for (int i=1,t,x;i<=m;i++){
		scanf("%d",&t);
		a[i].clear();
		while (t--){
			scanf("%d",&x);
			a[i].push_back(x);
			Hash[++hs]=x;
		}
	}
	Get_Hash();
	for (int i=1;i<=hs;i++)
		tre[i].clear();
	for (int i=1;i<=m;i++)
		for (int j=0;j<a[i].size();j++)
			tre[find(a[i][j])].push_back(i);
	memset(tot,0,sizeof tot);
	int ans=2147483647,L=0,R=0,cnt=0;
	while (R<hs){
		R++;
		for (int i=0;i<tre[R].size();i++){
			if (!tot[tre[R][i]])
				cnt++;
			tot[tre[R][i]]++;
		}
		while (cnt==m&&L<R){
			L++;
			ans=min(ans,Hash[R]-Hash[L]);
			for (int i=0;i<tre[L].size();i++){
				tot[tre[L][i]]--;
				if (!tot[tre[L][i]])
					cnt--;
			}
		}
	}
	printf("%d",ans);
	return 0;
}

  

posted @ 2017-08-25 15:33  zzd233  阅读(206)  评论(0编辑  收藏  举报