题解 P2564 【[SCOI2009]生日礼物】
需要将所有彩珠的位置从小到大排序;
枚举一个位置x,需要快速知道每种彩珠≤x的位置,这个需要将每种彩珠出现的位置按从大到小的顺序存在链表中;
一个优化:因为从大到小枚举x,所以可以将每种彩珠位置所在的链表中位置>x的节点都删除
附上代码
#include <iostream>
using namespace std;
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <memory.h>
#include <cstdlib>
const int N=1000005;
const int oo=2147483647;
typedef long long LL;
inline void get(int &x){char c=getchar();x=0;
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return ;
}
int n,k;
struct node{
LL x;
int id;
bool operator < (const node& y) const{
return x<y.x;
}
}p[N];
int len=0;
int a[N];
LL ans=0;
int maxm=0,minm=oo;
int main(){
get(n);get(k);
int i,j,x;
for(i=1;i<=k;i++){
int t;
get(t);
for(j=1;j<=t;j++){
get(x);
p[++len].x=x;
p[len].id=i;
maxm=max(x,maxm);
minm=min(x,minm);
}
}
sort(p+1,p+n+1);
j=x=0; ans=maxm-minm;
memset(a,0,sizeof(a));
for(i=1;i<=n;i++){
while(j<n&&x<k){
j++;
if(!a[p[j].id]) x++;
a[p[j].id]++;
}
if(x<k) break;
ans=min(ans,p[j].x-p[i].x);
a[p[i].id]--;
if(!a[p[i].id]) x--;
}
printf("%lld\n",ans);
return 0;
}