P2564 [SCOI2009]生日礼物

*传送

*预处理:把m个区间合并成一个大区间(按照横坐标排序即可)

*思路:因为我们要一段尽可能小的区间包含所有的彩带种类,我们不防开一个数组,记录当前区间内每种彩带多有多少个,从[1,1]开始,如果当前彩带种类<k,则右端点向右移,把该种彩带在区间内的数量+1,如果该种彩带的数量从0->1,即说明这是一条新彩带,彩带种类+1,当彩带种类==m时,记录下当前区间长度,把左端点向右移,把该种彩带在区间内的数量-1,如果该种彩带的数量从1->0,说明该种彩带不包含在区间里。彩带种类-1

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <queue>
 5 #include <cmath>
 6 using namespace std;
 7 int n,m,a[1000005],b[20005],k,l,r,t,ans=0;
 8 struct node{
 9     int pos,val;
10 }num[1000005];
11 bool cmp(node a,node b){
12     return a.pos<b.pos;
13 }
14 int main()
15 {
16 
17     scanf("%d%d",&n,&m);
18     for(int i=1;i<=m;i++){
19         scanf ("%d",&t);
20         for (int j = 1;j <= t;j++){
21             scanf ("%d",&num[++ans].pos);
22             num[ans].val=i;
23         }
24     }
25     sort(num+1,num+ans+1,cmp);
26     l=1; r=1; k=1; b[num[1].val]=1; int tmp=2000000005;
27     while(l<=r && r<=n){
28         while(k==m){
29             tmp=min(tmp,num[r].pos-num[l].pos);
30             b[num[l].val]--;
31             if(b[num[l].val]==0) k--;
32             l++;
33         }
34         r++, b[num[r].val]++;
35         if(b[num[r].val]==1) k++;
36     }
37     cout<<tmp<<endl;
38     return 0;
39 }
原文地址:https://www.cnblogs.com/very-beginning/p/12491130.html