*点击

[SCOI2009] 生日礼物

题目

Description

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

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

彩带的长度即为彩带开始位置到结束位置的位置差。

Input

第一行包含两个整数 N,KN,K,分别表示彩珠的总数以及种类数。

接下来 KK 行,每行第一个数为 TiTi,表示第 ii 种彩珠的数目。

接下来按升序给出 TiTi 个非负整数,为这 TiTi 个彩珠分别出现的位置。

Output

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

Sample Input

6 3
1 5
2 1 7
3 1 3 8

Sample Output

3

思路

用一个左指针表示彩带左端点,右指针一直往后移动;

在右指针往右移动的过程中判断左指针位置上的彩珠出现次数是否大于一次;

若左指针上彩珠出现次数大于一次,说明后面出现过这种类型的彩珠,开始位置的彩珠并不能对彩珠总种数没有影响,舍弃即可(左指针右移,且次数减一);

 

代码

复制代码
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const ll _=2e6+1;
ll n,m;
ll tot;
ll q[_];
map<ll,ll> f;
struct cow
{
    ll x,id;
}a[_];
bool cmp(cow a,cow b)
{
    return a.x<b.x;
}
int main()
{
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=m;i++)
    {
        ll x;
        scanf("%lld",&x);
        for(ll j=1;j<=x;j++)
        {
            a[++tot].id=i;
            scanf("%lld",&a[tot].x);
        }
    }
    sort(a+1,a+n+1,cmp);//按照位置排序
    ll ans=INT_MAX;
    ll head=1,sum=0;
    for(ll i=1;i<=n;i++)
    {
        if(!f[a[i].id])//统计出现的种类数
            sum++;
        f[a[i].id]++;//统计每个彩珠出现次数
        while(f[a[head].id]>1)//开始位置彩珠数大于一,则后面出现过这种彩珠
        {
            f[a[head].id]--;
            head++;//舍弃这个位置的彩珠
        }
        if(sum==m) ans=min(ans,a[i].x-a[head].x);//若彩带包含所以种数,则记录答案
    }
    printf("%lld",ans);
    return 0;
}
复制代码

 

 

 



如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   木偶人-怪咖  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?
*访客位置3D地图 *目录
点击右上角即可分享
微信分享提示