题目背景
四川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 }