luogu 2564 [SCOI2009]生日礼物

题目背景

四川2009NOI省选

题目描述

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

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

输入格式

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

输出格式

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

输入输出样例

输入 #1
6 3
1 5
2 1 7
3 1 3 8
输出 #1
3

说明/提示

【样例说明】

有多种方案可选,其中比较短的是1~5和5~8。后者长度为3最短。

【数据规模】

对于50%的数据, N≤10000;

对于80%的数据, N≤800000;

对于100%的数据,1≤N≤1000000,1≤K≤60,0≤珠子位置<231

Ti=n

分析

挺水的,

把所有的珠子按位置排序,用一个 long long 的变量存目前已经得到了那些颜色

另外用一个vis数组存有哪些颜色,有多少个(用于维护队列)

队列中保证至少有一种颜色只有一颗珠子

当队首的颜色有重复时,就弹出队首;

新位置的颜色不管重没重复都放入队尾,同时颜色的个数++;

如果已经达到全部颜色,就用队首与队尾更新ans

注意最好将ans的更新与i一一对应,不能漏掉第一次或最后一次更新

代码

 1 /*************************
 2 User:Mandy.H.Y
 3 Language:c++
 4 Problem:luogu
 5 Algorithm:
 6 Date:2019.8.30
 7 *************************/
 8 #include<bits/stdc++.h>
 9 #define Max(x,y) ((x) > (y) ? (x) : (y))
10 #define Min(x,y) ((x) < (y) ? (x) : (y))
11 
12 using namespace std;
13 
14 const int maxn =  1e6 + 5;
15 //数据范围 
16 int n,k,l,r,cnt,ans = 0;
17 long long color = 0;
18 int q[maxn],vis[70];
19 
20 struct Node{
21     int c,pos;
22     bool operator <(const Node &a)const {
23         return pos < a.pos ;
24     }
25 }node[maxn];
26 
27 template<class T>inline void read(T &x){
28     x = 0;bool flag = 0;char ch = getchar();
29     while(! isdigit(ch)) flag |= ch == '-',ch = getchar();
30     while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
31     if(flag) x = -x;
32 }
33 
34 template<class T>void putch(const T x){
35     if(x > 9) putch(x / 10);
36     putchar(x % 10 | 48);
37 }
38 
39 template<class T>void put(const T x){
40     if(x < 0) putchar('-'),putch(-x);
41     else putch(x);
42 }
43 
44 void file(){
45     freopen("2564.in","r",stdin);
46     freopen("2564.out","w",stdout);
47 }
48 
49 void readdata(){
50     read(n);read(k);
51     for(int i = 1;i <= k; ++ i){
52         int t;read(t);
53         for(int j = 1;j <= t; ++ j){
54             int x;read(x);
55             node[++cnt].c = i - 1;
56             node[cnt].pos = x;
57         }
58     }
59     
60     sort(node + 1,node + cnt + 1);
61 }
62 
63 void work(){
64     
65     long long maxcolor = (1LL << k) - 1;
66     ans = node[n].pos;
67     
68     for(int i = 1;i <= n; ++ i){
69 //        if(color == maxcolor) ans = min(ans,node[q[r-1]].pos - node[q[l]].pos);
70         q[r++] = i;vis[node[i].c]++;
71         color |= (1ll << (long long)node[i].c);
72         while(l < r && vis[node[q[l]].c] >= 2) vis[node[q[l]].c]--,l++; 
73         if(color == maxcolor) ans = min(ans,node[q[r-1]].pos - node[q[l]].pos);
74     }
75     
76 //    if(color == maxcolor) ans = min(ans,node[q[r-1]].pos - node[q[l]].pos);
77     //注意如果将这一句放在循环的第一句,最后一次更新l可能没有更新答案 
78     //以后注意写代码时,更新变量后一定紧跟更新答案 
79     
80     put(ans);
81 }
82 
83 int main(){
84 //    file();
85     readdata();
86     work();
87     return 0;
88 }
View Code
非做顽石不可,哪管他敬仰暗唾
原文地址:https://www.cnblogs.com/Mandy-H-Y/p/11433637.html