Luogu2564 [SCOI2009]生日礼物

原题链接:https://www.luogu.com.cn/problem/P2564

生日礼物

题目背景

四川2009NOI省选

题目描述

小西有一条很长的彩带,彩带上挂着各式各样的彩珠。已知彩珠有N个,分为K种。简单的说,可以将彩带考虑为x轴,每一个彩珠有一个对应的坐标(即位置)。某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上。

小布生日快到了,于是小西打算剪一段彩带送给小布。为了让礼物彩带足够漂亮,小西希望这一段彩带中能包含所有种类的彩珠。同时,为了方便,小西希望这段彩带尽可能短,你能帮助小西计算这个最短的长度么?彩带的长度即为彩带开始位置到结束位置的位置差。

输入格式

第一行包含两个整数N, K,分别表示彩珠的总数以及种类数。接下来K行,每行第一个数为Ti,表示第i种彩珠的数目。接下来按升序给出Ti个非负整数,为这Ti个彩珠分别出现的位置。

输出格式

输出应包含一行,为最短彩带长度。

输入输出样例

输入 #1
6 3
1 5
2 1 7
3 1 3 8
输出 #1
3

说明/提示

【样例说明】

有多种方案可选,其中比较短的是1 ~ 5和5 ~ 8。后者长度为3最短。

【数据规模】

对于50%的数据, N≤10000;

对于80%的数据, N≤800000;

对于100%的数据,1≤N≤1000000,1≤K≤60, 0 ≤ 0≤ 0珠子位置 < 2 31 <2^{31} <231

∑ T i = n \sum T_i =n Ti=n

题解

强化版的逛画展,思路可以说是一模一样:先找一个满足要求的区间,然后不断右移右端点,同时尝试右移左端点,更新答案。

代码

调了半天才发现右移左端点的部分忘加循环了,一次就只能移动到下一个横坐标,菜鸡流泪……

#include<bits/stdc++.h>
using namespace std;
const int M=1e6+5;
struct Ball{
    
    int pos,col;}bal[M];
bool cmp(Ball a,Ball b){
    
    return a.pos<b.pos;}
int n,k,tot,le,ri,cot[65],num,ans=INT_MAX;
void in()
{
    
    
    scanf("%d%d",&n,&k);
    for(int i=1,a;i<=k;++i)
    {
    
    
        scanf("%d",&a);
        for(;a--;bal[tot].col=i)scanf("%d",&bal[++tot].pos);
    }
}
void ac()
{
    
    
    sort(bal+1,bal+1+n,cmp);
    for(le=ri=1;ri<=n;++ri)
    {
    
    
        for(;bal[ri].pos==bal[ri+1].pos;++ri)if(!cot[bal[ri].col]++)++num;
        if(!cot[bal[ri].col]++)++num;
        if(num==k)break;
    }
    for(int flag,i;ri<=n;)
    {
    
    
        for(flag=1;flag;)
        {
    
    
            for(i=le;bal[i].pos==bal[i+1].pos;++i)if(cot[bal[le].col]<=1)flag=0;
            if(cot[bal[i].col]<=1)flag=0;
            if(flag)for(;le<=i;++le)--cot[bal[le].col];
        }
        ans=min(ans,bal[ri].pos-bal[le].pos);
        for(++ri;ri<=n&&bal[ri].pos==bal[ri+1].pos;++ri)++cot[bal[ri].col];++cot[bal[ri].col];
    }
    printf("%d\n",ans);
}
int main()
{
    
    
    in(),ac();
    //system("pause");
}

猜你喜欢

转载自blog.csdn.net/ShadyPi/article/details/113800601
今日推荐