NC20565 [SCOI2009]生日礼物
题目
题目描述
小西有一条很长的彩带,彩带上挂着各式各样的彩珠。已知彩珠有 个,分为 种。简单的说,可以将彩带考虑为 轴,每一个彩珠有一个对应的坐标(即位置)。某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上。 小布生日快到了,于是小西打算剪一段彩带送给小布。为了让礼物彩带足够漂亮,小西希望这一段彩带中能包含所有种类的彩珠。同时,为了方便,小西希望这段彩带尽可能短,你能帮助小西计算这个最短的长度么?彩带的长度即为彩带开始位置到结束位置的位置差。
输入描述
第一行包含两个整数 ,分别表示彩珠的总数以及种类数。
接下来 行,每行第一个数为 ,表示第 种彩珠的数目。接下来按升序给出 个非负整数,为这 个彩珠分别出现的位置。
输出描述
应包含一行,为最短彩带长度。
示例1
输入
6 3 1 5 2 1 7 3 1 3 8
输出
3
备注
对于 的数据, ;
对于 的数据, ;
对于 的数据,,,。
题解
知识点:离散化,双指针,枚举。
由于位置超数组模拟的限度,因此离散化每个位置和对应的彩灯类型,节约大部分无效空间。
按位置从小到大排序,注意到对于某一段恰好合法彩带,左端点向右移,右端点不需要复位,因为右端点是以右端点之前所有端点为左端点的合法最小右端点,符合尺取法。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; pair<int,int> bead[1000007];///离散化每个位置和对应的彩灯类型 60*10^6 int vis[67];///记录尺取区间的种类访问数 int main(){ std::ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int n,k; cin>>n>>k; int cnt = 0; for(int i = 0;i<k;i++){ int t; cin>>t; for(int j = 0;j<t;j++){ int pos; cin>>pos; bead[cnt++] = make_pair(pos,i); } } sort(bead,bead+cnt);///按位置从小到大排序 int l = 0,r = 0,sum = 0,len = ~(1<<31); while(l<n){ while(r<n && sum<k){ if(!vis[bead[r].second]) sum++; vis[bead[r].second]++; r++; }///注意r在合法区间的右侧+1位置,因为每次都是最后++,合法之后会再++ if(sum>= k) len = min(len,bead[r-1].first - bead[l].first);///注意距离而不是点个数,是两个位置的差不需要加1 vis[bead[l].second]--; if(!vis[bead[l].second]) sum--; l++; } cout<<len<<'\n'; return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16249698.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧