bzoj1293 生日礼物

来源:互联网 发布:淘宝客服评价回复话术 编辑:程序博客网 时间:2024/05/16 18:05

数轴上有k种颜色共n个点,求一个最短的区间,包含所有k中颜色的点。

关键词:枚举区间终点、点的单调性(保证遍历时,每个点仅经过一次)

枚举区间的终点,对于每个终点,寻找比该终点坐标小的且离该点最近的k个不同颜色点,记录最大值即该终点对应最短区间长度。观察可以发现,这些k个点的坐标总是随终点的坐标减小而减小的。因此在遍历过程中,每个点最多仅经过一次,知道枚举到以某个点为终点时,不存在某种颜色的点在该终点左侧。

技巧:将相同颜色的点的坐标按照从大到小建边连接起来,可以依次遍历

#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include<math.h>#define maxn 2000000#define ll long long#define INF 0x3f3f3f3f#define mem(a,b) memset(a,b,sizeof(a))using namespace std;int n,k;struct Edge{    int to,next;}edge[maxn];int head[100],tot,node[maxn],cnt,ans;void add(int u,int v){    edge[tot].to=v,edge[tot].next=head[u],head[u]=tot++;}bool cal(int u){    int mx=0;    for(int i=1;i<=k;i++){        while(edge[head[i]].to>u){            if(edge[head[i]].next==-1) return 0;            head[i]=edge[head[i]].next;        }        if(edge[head[i]].to<=u) mx=max(mx,u-edge[head[i]].to);    }    ans=min(ans,mx);    return 1;}int main(){    //freopen("a.txt","r",stdin);    scanf("%d%d",&n,&k);    mem(head,-1),tot=cnt=0,ans=INF;    int num,u;    for(int i=1;i<=k;i++){        scanf("%d",&num);        for(int j=1;j<=num;j++){            scanf("%d",&u);            add(i,u);            node[cnt++]=u;        }    }    sort(node,node+cnt);    for(int i=cnt-1;i>=0;i--){        if(node[i]!=node[i+1])            if(!cal(node[i])) break;    }    printf("%d\n",ans);}


0 0
原创粉丝点击