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
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; }