2020暑期多校D9-F 思路+证明
主为自用,欢迎指正。
https://ac.nowcoder.com/acm/contest/5674/F
前置知识:
尺取法:一种反复推进区间的头尾,求出满足条件的最小区间的技巧。
题意:
从n天中选m天,要让m天所穿的衣服价值的最大值与最小值差值最小。
思路:
由于每天有不定件衣服可选取,但是最多只有2e6件衣服,一维数组完全存得下,故想到排序,暴力每段长度为m的区间,若天数少了则向右拓展,维护最大值与最小值之间的差值。时间复杂度为O(n*n)。
后来直接TLE,故决定用尺取降低时间复杂度,尺取的核心在于对满足与不满足条件时的左右区间端点进行修改,故O(n)时间复杂度即可。
代码步骤:
将所有衣服按照价值升序存至一维数组,随后尺取,详细可见代码注释。
AC代码:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<math.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 2e6 + 10;
int Case;
int n, m;
int num;
int min1, max1 = 0;
int count1 = 0;
int ha[N];
struct point1 {
int v;
int l;
}p[N];
bool cmp1(point1 a, point1 b) {
return a.v < b.v;
}
void solve() {
int res = INF;
int cou = 0; //区间内不同天数
int s = 1;
for (int t = 1; t <= count1; t++) {
if (!ha[p[t].l])
cou++;
ha[p[t].l]++; //选择该天的衣服件数
while (cou == m) {
res = min(res, p[t].v - p[s].v); //选取最小差值
ha[p[s].l]--; //则第p[s].l天的衣服可去掉
if (!ha[p[s].l])//若去掉第s小件衣服后,改天p[s].l不再被选取则选取不同天数减一
cou--;
s++; //每次cou==m,必定使原点前进
}
}
printf("%d\n", res);
}
int main() {
scanf("%d%d", &n, &m);
memset(p, 0, sizeof(p));
memset(ha, 0, sizeof(ha));
for (int i = 1; i <= n; i++) {
scanf("%d", &num);
for (int j = 1; j <= num; j++) {
scanf("%d", &p[++count1].v);
p[count1].l = i;
}
}
sort(p + 1, p + count1 + 1, cmp1);
solve();
// for (int i = 0; i < count1; i++)
// printf("%d", p[i].v);
}简单图证:
注:
数据给的很差,默认最小价值差为,最小价值衣服为端点至m件不同衣服的最大值的查值。



京公网安备 11010502036488号