打卡信奥刷题(2618)用C++实现信奥题 P2564 [SCOI2009] 生日礼物

P2564 [SCOI2009] 生日礼物

题目背景

四川2009NOI省选

题目描述

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

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

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

输入格式

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

接下来 KKK 行,每行第一个数为 TiT_iTi,表示第 iii 种彩珠的数目。

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

输出格式

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

输入输出样例 #1

输入 #1

6 3
1 5
2 1 7
3 1 3 8

输出 #1

3

说明/提示

样例说明

有多种方案可选,其中比较短的是 1∼51 \sim 5155∼85 \sim 858。后者长度为 333,更短,故答案为 333

数据范围

对于 50%50\%50% 的数据,N≤104N \le 10^4N104

对于 80%80\%80% 的数据,N≤8×105N \le 8 \times 10^5N8×105

对于 100%100\%100% 的数据,1≤N≤106,1≤K≤601 \le N \le 10^6, 1 \le K \le 601N106,1K600≤0 \le0 珠子位置 <231< 2^{31}<231,且 ∑Ti=N\sum T_i = NTi=N

C++实现

#include<bits/stdc++.h>
using namespace std;
const int N=1000005;
int l,r,n,m,k,t,b[105],cnt,ans;
struct node{
	int val,id;
}a[N];
bool cmp(node a,node b){
	return a.val<b.val;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)	{
		scanf("%d",&k);
		for(int j=1;j<=k;j++)		{
			scanf("%d",&a[++t].val);
			a[t].id=i;
		}
	}
	ans=1e9;
	sort(a+1,a+t+1,cmp);//排序是为了使位置相同的"彩珠"在一起
	l=r=1;b[a[1].id]=1;cnt=1;
	for(int i=2;i<=n;i++)
		if(a[i].val==a[i-1].val)		{
			r++;
			b[a[i].id]++;
			if(b[a[i].id]==1)cnt++;
		}
		else break;
	while(l<=n&&r<=n)	{
		if(cnt==m)		{
			ans=min(ans,a[r].val-a[l].val);
			b[a[l].id]--;if(b[a[l].id]==0)cnt--;
			l++;if(l>n)break;//注意边界
			while(a[l].val==a[l-1].val)			{
				b[a[l].id]--;if(b[a[l].id]==0)cnt--;
				l++;if(l>n)break;//注意边界
			}
		}
		else{//不满足条件
			r++;if(r>n)break;//注意边界
			b[a[r].id]++;if(b[a[r].id]==1)cnt++;
			while(a[r+1].val==a[r].val)			{
				r++;if(r>n)break;//注意边界
				b[a[r].id]++;if(b[a[r].id]==1)cnt++;
			}
		}
	}
	cout<<ans;
}

在这里插入图片描述

后续

接下来我会不断用C++来实现信奥比赛中的算法题、GESP考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值