bzoj 1293: [SCOI2009]生日礼物

链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1293

思路:用静态链表存一下这些点,然后枚举终点,当前终点枚举k种珠子,分别找到每一种种类在终点之前最近的珠子,保存下距离,维护所有种类珠子离终点的最大值,这就是以当前点为终点的最短场合,最后取所有终点的最短长度就好了。

 

 实现代码:

#include<bits/stdc++.h>
using namespace std;
const int M = 1e6 + 10;
const int inf = 0x3f3f3f3f;
int n,m,ans,t;
int a[M],nex[M],head[100],b[M];
bool cal(int x){
    int tmp = 0;
    for(int i = 1;i <= m;i ++){
        while(a[head[i]] > x){
            if(nex[head[i]] == 0) return 0;  //这种类的珠子坐标都大于当前终点,不能取得k种直接跳出
            head[i] = nex[head[i]];  //更换尾节点,因为是从大到小枚举,之前的尾节点在以后也用不到,直接替换掉就好了
        }
        if(a[head[i]] <= x) tmp = max(tmp,x - a[head[i]]);
    }
    ans = min(tmp,ans);
    return 1;
}

int main()
{
    int x,cnt = 0;
    cin>>n>>m;
    for(int i = 1;i <= m;i ++){
        cin>>t;
        for(int j = 1;j <= t;j ++){
            cin>>x;
            a[++cnt] = x;
            nex[cnt] = head[i];
            head[i] = cnt;
            b[cnt] = x;
        }
    }
    ans = inf;
    sort(b+1,b+1+cnt);
    for(int i = cnt;i >= 1;i --){
        if(b[i] != b[i+1]){
            if(!cal(b[i])) break;  //因为是从大到小的,当前终点无法取得k种,比他小的更不可能,直接跳出就好了
        }
    }
    cout<<ans<<endl;
}

 

posted @ 2019-03-20 22:07  冥想选手  阅读(123)  评论(0编辑  收藏  举报