bzoj1293[SCOI2009]生日礼物

bzoj1293[SCOI2009]生日礼物

题意:

数轴上N个点,分为K种。可以有多个点出现在同一个位置上。需要一个最短区间使里面有K种点,求这个区间长度。N≤1000000

题解:

先排序,然后用两个指针分别指向区间两个端点,每次l指针往左移并更新答案直到区间里没有K种点,再把r指针向右移直到区间里有K种点,更新一下答案。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define INF 0x3fffffff
 6 using namespace std;
 7 
 8 struct ball{int a,b;}; ball balls[1000500];
 9 bool cmp(ball a,ball b){return a.a<b.a;}
10 int n,k,l,r,bs,kn[70],ks,mn;
11 int main(){
12     scanf("%d%d",&n,&k);
13     inc(i,1,k){
14         int x,y; scanf("%d",&x); inc(j,1,x)scanf("%d",&y),balls[++bs]=(ball){y,i};
15     }
16     sort(balls+1,balls+1+bs,cmp); l=1; r=0;
17     memset(kn,0,sizeof(kn)); ks=0; mn=INF;
18     while(ks<k){
19         if(r<n){r++; kn[balls[r].b]++; if(kn[balls[r].b]==1)ks++;}
20         while(r<n&&balls[r].a==balls[r+1].a){r++; kn[balls[r].b]++; if(kn[balls[r].b]==1)ks++;}
21         if(r==n)break;
22     }
23     if(ks==k)mn=min(mn,balls[r].a-balls[l].a);
24     while(1){
25         while(l<r&&balls[l].a==balls[l+1].a){kn[balls[l].b]--; if(kn[balls[l].b]==0)ks--; l++;}
26         if(l<r){kn[balls[l].b]--; if(kn[balls[l].b]==0)ks--; l++;}
27         if(ks==k)mn=min(mn,balls[r].a-balls[l].a);else{
28             while(ks<k){
29                 if(r<n){r++; kn[balls[r].b]++; if(kn[balls[r].b]==1)ks++;}
30                 while(r<n&&balls[r].a==balls[r+1].a){r++; kn[balls[r].b]++; if(kn[balls[r].b]==1)ks++;}
31                 if(r==n)break;
32             }
33             if(ks==k)mn=min(mn,balls[r].a-balls[l].a);
34         }
35         if(l==r)break;
36     }
37     printf("%d",mn); return 0;
38 }

 

20160602

posted @ 2016-07-20 19:27  YuanZiming  阅读(221)  评论(0编辑  收藏  举报