F.Groundhog Looking Dowdy(优秀的尺取)

题目链接:F·Groundhog Looking Dowdy

题目大意

给你两个数 n 和 m n 和 m nm 从这 n n n天中选取 m m m天,每天选取一件衣服,使得这 m m m件衣服的最大值与最小值的差值最小。
接下来 n n n行,每行的第一个数表示这天有多少件衣服,后面是每件衣服的数值。

解题思路

我们可以用一个结构体来存储每件衣服的元素
i d   表 示 这 件 衣 服 属 于 第 几 天 的 id \ 表示这件衣服属于第几天的 id 
v a l   表 示 这 件 衣 服 的 值 是 多 少 val \ 表示这件衣服的值是多少 val 
然后我们通过根据 v a l val val 值的大小对结构体进行排序。排之后我们就可以才用尺取从前往后慢慢进行了,注意的是尺取的距离是id不同的个数,而不是直接按照结构体数组的长度进行的。 具体细节就看代码的注释吧
由于这道题的数据好像有问题所以,本代码只过了牛客的数据。
这里提供一组数据可以

4 3
3 1 5 9
2 7 8
3 2 4 8
3 4 5 7

欢迎巨佬们进行hack

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx =2000200;
const ll inf = 1e18;
const ll mod = 998244353;

struct node{
	int val,id;
}a[mx];
int vis[mx];

bool cmp(node a,node b){
	return a.val<b.val;
} 

int main(){
	ios::sync_with_stdio(0);
	int n,m;cin>>n>>m;
	int cnt=0;
	for(int i=1,x;i<=n;i++){
		cin>>x;
		while(x--){
			cnt++;
			cin>>a[cnt].val;
			a[cnt].id=i;	
		}
	}
// 按照 val 的从小到大排序	
	sort(a+1,a+cnt+1,cmp);
// k 表示当前尺取范围内有多少个不同元素	
	int k=0,l=1,r=0;
	while(k<m){
		r++;
// vis 值等 0 说明尺取范围中还未出现过这天的衣服		
		if(!vis[a[r].id]){
			vis[a[r].id]++;
			k++;
		}
	}		
	int ans=2000000000;
	while(r<=cnt){
// 计算这 m 天的差值		
		ans=min(ans,a[r].val-a[l].val);
		vis[a[l].id]--;//用过之后可以给其减去标记 
		l++;
// 如果 这个vis等于一说明和上一不是一天的,l向后移动 
		if(vis[a[l].id]) k--;
		else vis[a[l].id]++;
/* 
如果这一天有多个衣服可以选择,应当都试下
2 2
1 3
2 1 2
这样排完序是 1 2 3
第一次 ans=3-1=2;
但是 第二天还可以再选 2 使的值更小 
所以需要重新对其标记 
*/	
// 如果 k 值减少, r应该向后继续滚动 
		while(k<m&&r<=cnt){
			r++;
			if(!vis[a[r].id]){
				vis[a[r].id]++;
				k++;
			}
		}
	}
	cout<<ans<<"\n";
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值