生日礼物简单题解

题目来源:[SCOI2009]生日礼物 - 题目 - 黑暗爆炸OJ

原题:

Description

小西有一条很长的彩带,彩带上挂着各式各样的彩珠。已知彩珠有N个,分为K种。简单的说,可以将彩带考虑为x轴,每一个彩珠有一个对应的坐标(即位置)。某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上。 小布生日快到了,于是小西打算剪一段彩带送给小布。为了让礼物彩带足够漂亮,小西希望这一段彩带中能包含所有种类的彩珠。同时,为了方便,小西希望这段彩带尽可能短,你能帮助小西计算这个最短的长度么?彩带的长度即为彩带开始位置到结束位置的位置差。

Input

第一行包含两个整数N, K,分别表示彩珠的总数以及种类数。接下来K行,每行第一个数为Ti,表示第i种彩珠的数目。接下来按升序给出Ti个非负整数,为这Ti个彩珠分别出现的位置。

Output

应包含一行,为最短彩带长度。

题意:一条彩带挂了总共n个彩珠,共k中分布在彩带上,截一段彩带,要求所有种类的彩带都要有,求最短需要长的彩带

题解思路:

定义一个结构体,用于存储彩珠的种类和位置,然后用一个数组存储,并排序,这样就能得到一个非常形象的彩带,在存储彩珠种类和位置的数组中,用双指针作为一个彩带的左边和右边,并用一个数组记录每种彩珠的数量,当区间的种类数等于k时,寻找最小值,再继续移动指针。

代码实现:

#include <iostream>
#include <algorithm>
#include<string>
#include<queue>
#include<map>
#include<cstdio>
#define ll long long
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<stack>
const int md=1e9+7;
using namespace std;
const int maxn=1000008;
struct node{
	int x,cor;
	bool operator <(const node&a)const{
		return x<a.x;//按照位置排序 
	}
}w[maxn];//描述彩带状况的数组 
const int inf=0x3f3f3f3f;
int num[66];//记录每种彩珠的数量 
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n,k,s=0,tp=0;//s用于记录w元素数量 ,tp记录区间内元素的种类 
cin>>n>>k;
for(int i=1;i<=k;i++)
{
	int t;
	cin>>t;//彩珠数量 
	while(t--)
	{
		int x;//输入位置 
		cin>>x;
		w[++s]={x,i};//加入数组 
	}
}
sort(w+1,w+s+1);
int r=0,l=0,ans=(1ll<<31)-1;//r为右指针,l为左指针 
while(l<n)
{
	l++;//左指针右移 
	if(l>1)
	{
		num[w[l-1].cor]--;//l移之前的彩珠现在在区间外了,所以他的所属的颜色数量减1 
		if(num[w[l-1].cor]==0)tp--;//如果这个颜色没有了,那么彩珠种类减一 
	}
	while(tp<k&&r<n)
	{
		r++;//移动有指针 
		if(num[w[r].cor]==0)tp++;//如果右移后得到一个区间内没有的彩珠颜色,那么彩珠种类加1 
		num[w[r].cor]++;	//该颜色加1 
	}
	if(tp==k)//如果颜色种类等于k,满足条件 
	{
		if(ans>w[r].x-w[l].x)
		ans=w[r].x-w[l].x;
	}
}
	cout<<ans;
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值