【单调队列】生日礼物

 题目描述 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 }

 

转载于:https://www.cnblogs.com/algonote/p/7095856.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值