题目链接:F·Groundhog Looking Dowdy
题目大意
给你两个数
n
和
m
n 和 m
n和m 从这
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;
}