首页 > 代码库 > 【单调队列】[SCOI2009]生日礼物

【单调队列】[SCOI2009]生日礼物

题目描述

小西有一条很长的彩带,彩带上挂着各式各样的彩珠。已知彩珠有N个,分为K种。简单的说,可以将彩带考虑为x轴,每一个彩珠有一个对应的坐标(即位置)。某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上。

小布生日快到了,于是小西打算剪一段彩带送给小布。为了让礼物彩带足够漂亮,小西希望这一段彩带中能包含所有种类的彩珠。同时,为了方便,小西希望这段彩带尽可能短,你能帮助小西计算这个最短的长度么?彩带的长度即为彩带开始位置到结束位置的位置差。

输入输出格式

输入格式:

 

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

 

输出格式:

 

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

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

 

【单调队列】[SCOI2009]生日礼物