洛谷 P10710 [NOISG 2024 Prelim] School Photo 题解
洛谷 P10710 [NOISG 2024 Prelim] School Photo 题解
免责声明:此题解的思路来自洛谷的Moya_Rao
完整题目
P10710 [NOISG 2024 Prelim] School Photo
题目背景
翻译自 NOI SG 2024 Prelim C.School Photo。
题目描述
Zane 是 NOI 学校的校长。NOI 学校有 \(n\) 个班,每个班有 \(s\) 名同学。第 \(i\) 个班中的第 \(j\) 名同学的身高是 \(a_{i,j}\)。
现在 Zane 想从每个班上选出一名同学拍照,使得这 \(n\) 名同学中最高的同学和最低的同学的身高差最小。
请你输出这个最小值。输入格式
第一行,两个整数 \(n,s\);
接下来 \(n\) 行,每行 \(s\) 个整数,表示 \(a\)。输出格式
一行一个整数表示答案。
输入输出样例 #1
输入 #1
2 3 2 1 8 5 4 7输出 #1
1输入输出样例 #2
输入 #2
3 3 3 1 4 2 7 18 9 8 10输出 #2
4说明/提示
【样例 #2 解释】
选择 \(a_{1,3},a_{2,2},a_{3,2}\),答案为 \(8-4=4\)。
【数据范围】
\(\text{Subtask}\) 分值 特殊性质 \(0\) \(0\) 样例 \(1\) \(11\) \(n=2\) \(2\) \(22\) \(n,s\le100\) \(3\) \(9\) \(n,s\le250\) \(4\) \(33\) \(n,s\le500\) \(5\) \(25\) 无 对于 \(100\%\) 的数据,\(1\le n,s \le 1000,1\le a_{i,j} \le 10^9\)。
1. 读题
这道题其实和洛谷 P1638 逛画展很像。题目大意:一所学校有 \(n\) 个班级,每个班级有 \(s\) 人。现在要在每个班里选出一个人进行拍照。为了照片的美观性,要使选出的这 \(n\) 个人中最高的人与最矮的人的身高差距最小,请你求出这个最小值。
2. 解题思路
用双指针滑动窗口的方法解题,如果班级种类不够了,就把\(r\)指针右移,然后判断这个人是不是新的班级的人,如果是,计数器++。等班级种类足够的时候,我们就把多余的人去掉,也就是说,把当前窗口中同一个班级的同学去除。删完人以后,再看看班级种类数是不是正好为 n。如果是的话,就尝试更新答案。
3.代码片段分析
- 数据定义
#include<bits/stdc++.h>
using namespace std;
const int N=1e6;
struct st{
int c,h;
//c:班级(class)。
//h:身高(heit)。
}a[N];
int v[N];//当前窗口内班级i的学生数量。
int n,s,cnt;//输入变量。
//cnt:总学生数。
//(其他变量与题目描述一致)。
int l=1,r=1,num=1,ans=1e9;//滑动窗口变量。
//l:左指针。
//r:右指针。
//num:当前窗口内不同班级的数量。
//ans:记录答案,因为后面要打擂台,所以要开大点。
bool cmp(st x,st y){//排序辅助,按身高排序。
return x.h<y.h;
}
- 数据读入
cin>>n>>s;
for(int i=1;i<=n;i++)
for(int j=1;j<=s;j++){
int x;
cin>>x;
a[++cnt]=st{i,x};//变量i遍历的是班级,把i(班级)和x(身高)存入数组。
}
- 双指针操作(核心部分)
sort(a+1,a+cnt+1,cmp);//按身高排序。
v[a[1].c]=1;//初始化
while(l<=r&&r<=cnt){//双指针(滑动窗口)。
//l<r:左指针不超过右指针。
//r<cnt:右指针不超过总学生数。
while(num<=n&&r<cnt){//窗口班级个数不超过班级总数。
v[a[++r].c]++;//累加
if(v[a[r].c]==1) num++;//如果a[r].c只第有一个,那就视为多了一个班级的学生。
}
while(v[a[l].c]>1) v[a[l++].c]--;//如果有多余班级的人,删掉
ans=min(ans,a[r].h-a[l].h);//如果正好满足,更新答案,打擂台。
v[a[l].c]--;
if(v[a[l].c]==0) num--;//把当前这个人删掉,
//由于他没有被上面的 while 删掉,因此他是这个班级的最后一员
//所以班级种类减少了
}
cout<<ans;
return 0;
4. AC代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6;
struct st{
int c,h;
}a[N];
int v[N];
int n,s,cnt;
int l=1,r=1,num=1,ans=1e9;
bool cmp(st x,st y){
return x.h<y.h;
}
int main(){
cin>>n>>s;
for(int i=1;i<=n;i++)
for(int j=1;j<=s;j++){
int x;
cin>>x;
a[++cnt]=st{i,x};
}
sort(a+1,a+cnt+1,cmp);
v[a[1].c]=1;
while(l<=r&&r<=cnt){
while(num<=n&&r<cnt){
v[a[++r].c]++;
if(v[a[r].c]==1) num++;
}
while(v[a[l].c]>1) v[a[l++].c]--;
ans=min(ans,a[r].h-a[l].h);
v[a[l].c]--;
if(v[a[l].c]==0) num--;
}
cout<<ans;
return 0;
}
如果对你有帮助,点个赞再走吧!谢谢!有什么问题请及时指出
浙公网安备 33010602011771号