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