题目描述 Description
小西有一条很长的彩带,彩带上挂着各式各样的彩珠。已知彩珠有N个,分为K种。简单的说,可以将彩带考虑为x轴,每一个彩珠有一个对应的坐标(即位置)。某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上。
小布生日快到了,于是小西打算剪一段彩带送给小布。为了让礼物彩带足够漂亮,小西希望这一段彩带中能包含所有种类的彩珠。同时,为了方便,小西希望这段彩带尽可能短,你能帮助小西计算这个最短的长度么?彩带的长度即为彩带开始位置到结束位置的位置差。
输入描述 Input Description
第一行包含两个整数N, K,分别表示彩珠的总数以及种类数。接下来K行,每行第一个数为Ti,表示第i种彩珠的数目。接下来按升序给出Ti个非负整数,为这Ti个彩珠分别出现的位置。
输出描述 Output Description
包含一行,为最短彩带长度。
样例输入 Sample Input
6 3
1 5
2 1 7
3 1 3 8
样例输出 Sample Output
3
数据范围及提示 Data Size & Hint
对于50%的数据, N≤10000;
对于80%的数据, N≤800000;
对于100%的数据,1≤N≤1000000,1≤K≤60,0≤Ti<231
开始先把每种颜色的第一个球push入优先队列,然后每次pop出状态队列中最靠左的球,再插入这个球所属颜色队列的下一个球,更新ans的值。
这样就能保持状态队列中始终有k个颜色各不相同的球。
不难证明当其中一种颜色队列的所有球pop过后,继续贪心一定不能得到更优的ans,所以这时直接break输出答案就行了。
1 #include <cstdio> 2 #include <vector> 3 #include <queue> 4 using namespace std; 5 #define INT_MAX 2147483647 6 int n,k,t[60],x,ans=INT_MAX; 7 vector<int> p[60]; 8 struct ball{ 9 int num,clr; 10 bool operator < (const ball &a) const { 11 return p[clr][num]>p[a.clr][a.num]; 12 } 13 }; 14 priority_queue<ball> que;//用来存放当前所选k个球的状态 15 int main() 16 { 17 scanf("%d%d",&n,&k); 18 for (int i=0;i<k;i++) 19 { 20 scanf("%d",&t[i]); 21 for (int j=0;j<t[i];j++) 22 { 23 scanf("%d",&x); 24 p[i].push_back(x); 25 } 26 } 27 int l=INT_MAX,r=0; 28 for (int i=0;i<k;i++)//插入所有颜色队列中的第一个球 29 { 30 ball tball; 31 tball.num=0; 32 tball.clr=i; 33 int tballpos=p[tball.clr][tball.num]; 34 if (tballpos<l) l=tballpos; 35 if (tballpos>r) r=tballpos; 36 que.push(tball); 37 } 38 ans=r-l;//计算初始状态的ans 39 for (int i=0;i<n-k;i++) 40 { 41 ball pball,tball; 42 pball=que.top();//当前状态中最靠左的球 43 que.pop(); 44 if (pball.num==t[pball.clr]-1) break; 45 46 tball.num=pball.num+1;//当前状态中最靠左的球所在颜色队列的下一个球 47 tball.clr=pball.clr; 48 int tballpos=p[tball.clr][tball.num]; 49 que.push(tball); 50 51 pball=que.top();//当前状态中第二靠左的球 52 int pballpos=p[pball.clr][pball.num]; 53 54 l=pballpos;//重新计算左右边界 55 if (tballpos<l) l=tballpos; 56 if (tballpos>r) r=tballpos; 57 if (r-l<ans) ans=r-l; 58 } 59 printf("%d\n",ans); 60 }