BZOJ 1293: [SCOI2009]生日礼物 贪心

1293: [SCOI2009]生日礼物

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2513  Solved: 1370
[Submit][Status][Discuss]

Description

小西有一条很长的彩带,彩带上挂着各式各样的彩珠。已知彩珠有N个,分为K种。简单的说,可以将彩带考虑为x轴,每一个彩珠有一个对应的坐标(即位置)。某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上。 小布生日快到了,于是小西打算剪一段彩带送给小布。为了让礼物彩带足够漂亮,小西希望这一段彩带中能包含所有种类的彩珠。同时,为了方便,小西希望这段彩带尽可能短,你能帮助小西计算这个最短的长度么?彩带的长度即为彩带开始位置到结束位置的位置差。

Input

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

Output

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

Sample Input

6 3

1 5

2 1 7

3 1 3 8

Sample Output

3

HINT

有多种方案可选,其中比较短的是1~5和5~8。后者长度为3最短。
【数据规模】
对于50%的数据, N≤10000;
对于80%的数据, N≤800000;
对于100%的数据,1≤N≤1000000,1≤K≤60,0≤彩珠位置<2^31。

题意:在数轴上求一个最短区间包含k种颜色的点。

算法:贪心;

枚举选择区间有点像队列的操作。

读入的时候先用一个now数组记录第i种颜色被选到的点的在数轴上位置,用一个places数组记录下标。(由于是按升序读入,所以不用多一步sort)

初始状态即为每种颜色的第一个点的最大最小值的差,样例为max(5,1,1)-min(5,1,1)。

所以我们往后枚举区间的时候就贪心地把当前区间最左边的点覆盖同种颜色的下一个点,然后最左边的点指针右移到下个点(如果最左边的点有多个,则选择它同种颜色的点最近的一个) 重复此操作,找出最大最小值并更新答案,操作次数固定为n-k+1.所以时间效率应该是O((n-k+1)*k)?

由于T[i]没给范围,所以二维数组开到最大会MLE。

代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define inf 0x7f7f7f7f;
 6 using namespace std;
 7 int n,m;
 8 int i,j;
 9 int l,hh;
10 long long ans,maxn,minn;
11 long long now[61],places[61];
12 int counts[61],num[61];
13 int a[61][100001];
14 int main()
15 {
16     scanf("%d%d",&n,&m);
17     for (i=1;i<=m;i++) {
18       scanf("%d",&num[i]);
19         for (j=1;j<=num[i];j++) {
20           scanf("%d",&a[i][j]);
21           if (j==1) {
22           now[i]=a[i][j];//记录位置
23           places[i]=j;//记录下标
24         }
25         }
26     }
27     ans=inf;
28     while (hh!=n-m+1) {
29         maxn=-inf; minn=inf; l=0;hh++;
30         for (i=1;i<=m;i++) {
31           if (now[i]>maxn) maxn=now[i];
32           if (now[i]<minn) {
33             minn=now[i]; l=i;
34     }
35         if (now[i]==minn) {
36          if (a[i][places[i]+1]<=a[l][places[l]+1]){
37            minn=now[i];
38            l=i;
39             }
40         }
41     }
42     //printf("%d %d\n",maxn,minn);
43           if (places[l]!=num[l]) {
44             now[l]=a[l][places[l]+1];
45             places[l]++;
46             //pos=places[i];
47         }//贪心移动区间
48         if (maxn-minn<ans) ans=maxn-minn; //更新答案
49
50     }
51     printf("%lld",ans);
52 }
53         

时间: 2024-10-03 23:06:45

BZOJ 1293: [SCOI2009]生日礼物 贪心的相关文章

bzoj 1293: [SCOI2009]生日礼物

Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1559  Solved: 848[Submit][Status][Discuss] Description 小西有一条很长的彩带,彩带上挂着各式各样的彩珠.已知彩珠有N个,分为K种.简单的说,可以将彩带考虑为x轴,每一个彩珠有一个对应的坐标(即位置).某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上. 小布生日快到了,于是小西打算剪一段彩带送给小布.为了让礼物彩带足够漂亮,小西希望这一段彩

BZOJ 1293 SCOI2009 生日礼物 堆

题目大意:给定一个数轴上n个点,每个点有一种颜色,一共k种颜色,求一个最短的区间,包含所有k种颜色 卡了一段时间0.0 一开始想二分答案啥的 后来发现数据范围太大写不了0.0 后来去找题解才发现尼玛真巧妙 维护一个堆 将每种颜色的第一个珠子加入堆 然后不断把最左侧的珠子取出,加入该种颜色的下一个 同时更新ans 果然这么大数据范围还是要用堆这种常数小的数据结构啊0.0 我手写了堆却开了STL的queue 0.0 不要说我有病我只是不习惯STL的堆罢了 #include<queue> #incl

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

一开始用了复杂度看起来对实则常数巨大的线段树+hash--后来发现队列就行-- 把珠子按位置排序,然后用队列维护一段,枚举右端点更新答案即可 #include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int N=1000005,inf=2147483647; int n,m,s[65],ans=inf,tot,sum,l=1,r; struct qwe { int

1293: [SCOI2009]生日礼物

1293: [SCOI2009]生日礼物 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1096  Solved: 584[Submit][Status] Description 小西有一条很长的彩带,彩带上挂着各式各样的彩珠.已知彩珠有N个,分为K种.简单的说,可以将彩带考虑为x轴,每一个彩珠有一个对应的坐标(即位置).某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上. 小布生日快到了,于是小西打算剪一段彩带送给小布.为了让礼物彩带足

1293: [SCOI2009]生日礼物 - BZOJ

Description 小西有一条很长的彩带,彩带上挂着各式各样的彩珠.已知彩珠有N个,分为K种.简单的说,可以将彩带考虑为x轴,每一个彩珠有一个对应的坐标(即位置).某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上. 小布生日快到了,于是小西打算剪一段彩带送给小布.为了让礼物彩带足够漂亮,小西希望这一段彩带中能包含所有种类的彩珠.同时,为了方便,小西希望这段彩带尽可能短,你能帮助小西计算这个最短的长度么?彩带的长度即为彩带开始位置到结束位置的位置差.Input 第一行包含两个整数N,

bzoj1293[SCOI2009]生日礼物 尺取法

1293: [SCOI2009]生日礼物 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2838  Solved: 1547[Submit][Status][Discuss] Description 小西有一条很长的彩带,彩带上挂着各式各样的彩珠.已知彩珠有N个,分为K种.简单的说,可以将彩带考虑为x轴,每一个彩珠有一个对应的坐标(即位置).某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上. 小布生日快到了,于是小西打算剪一段彩带送给小

矩阵乘法专题1——bzoj 1297 [SCOI2009] 迷路题解

题目链接 题意:给两个长度分别为n和m的序列,现在有两种操作:1.分别选择两个序列的一个非空前缀,切两个前缀的最后一位相同,删除之,得到1分(只累计),消耗e:2.直接删除两个序列,消耗值定于两个序列之前删除的元素个数之和,并且使得得到的分有效(之前没有有效分) 分析: 首先,问题其实就是转化成,进行若干次操作1,然后进行操作2 还要找到一个判别标准,来评判较优的状态(贪心) 每次的消耗值比较大,其实可以计算出最大的删除次数,这个值不是很大 状态表示: 简单的,一个状态可以表示为串A的位置.串B

BZOJ 1296: [SCOI2009]粉刷匠

BZOJ 1296: [SCOI2009]粉刷匠 Description windy有 N 条木板需要被粉刷. 每条木板被分为 M 个格子. 每个格子要被刷成红色或蓝色. windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色. 每个格子最多只能被粉刷一次. 如果windy只能粉刷 T 次,他最多能正确粉刷多少格子? 一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷. Input 输入文件paint.in第一行包含三个整数,N M T. 接下来有N行,每行一个长度为M的字符串,

BZOJ 1293 生日礼物

某一年的四川省选. 枚举每个彩珠,在它前面的所有种类的彩珠中寻找和它距离最大的(这一段距离一定囊括了所有彩珠)然后更新答案. 为了方便,我们将彩珠排序并另外构成链表形式(也是倒序). 然而这么水的题ziliuziliu还是没有很好想出来..不知道怎么回事.这道题其实蛮简单的啊. #include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define inf 0x7ffffff