题目来源:[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;
}