[SCOI2009] 生日礼物
题目
Description
小西有一条很长的彩带,彩带上挂着各式各样的彩珠。已知彩珠有 NN 个,分为 KK 种。简单的说,可以将彩带抽象为一个 x 轴,每一个彩珠有一个对应的坐标(即位置)。某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上。
小布的生日快到了,于是小西打算剪一段彩带送给小布。为了让礼物彩带足够漂亮,小西希望这一段彩带中能包含所有种类的彩珠。同时,为了方便,小西希望这段彩带尽可能短,你能帮助小西计算这个最短的长度么?
彩带的长度即为彩带开始位置到结束位置的位置差。
Input
第一行包含两个整数 N,KN,K,分别表示彩珠的总数以及种类数。
接下来 KK 行,每行第一个数为 TiTi,表示第 ii 种彩珠的数目。
接下来按升序给出 TiTi 个非负整数,为这 TiTi 个彩珠分别出现的位置。
Output
输出应包含一行,为最短彩带长度。
Sample Input
6 3 1 5 2 1 7 3 1 3 8
Sample Output
3
思路
用一个左指针表示彩带左端点,右指针一直往后移动;
在右指针往右移动的过程中判断左指针位置上的彩珠出现次数是否大于一次;
若左指针上彩珠出现次数大于一次,说明后面出现过这种类型的彩珠,开始位置的彩珠并不能对彩珠总种数没有影响,舍弃即可(左指针右移,且次数减一);
代码
#include<bits/stdc++.h> typedef long long ll; using namespace std; const ll _=2e6+1; ll n,m; ll tot; ll q[_]; map<ll,ll> f; struct cow { ll x,id; }a[_]; bool cmp(cow a,cow b) { return a.x<b.x; } int main() { scanf("%lld%lld",&n,&m); for(ll i=1;i<=m;i++) { ll x; scanf("%lld",&x); for(ll j=1;j<=x;j++) { a[++tot].id=i; scanf("%lld",&a[tot].x); } } sort(a+1,a+n+1,cmp);//按照位置排序 ll ans=INT_MAX; ll head=1,sum=0; for(ll i=1;i<=n;i++) { if(!f[a[i].id])//统计出现的种类数 sum++; f[a[i].id]++;//统计每个彩珠出现次数 while(f[a[head].id]>1)//开始位置彩珠数大于一,则后面出现过这种彩珠 { f[a[head].id]--; head++;//舍弃这个位置的彩珠 } if(sum==m) ans=min(ans,a[i].x-a[head].x);//若彩带包含所以种数,则记录答案 } printf("%lld",ans); return 0; }

浙公网安备 33010602011771号