1 条题解
-
0
自动搬运
来自洛谷,原作者为

一扶苏一
休息结束。邮箱 yifusuyi@qq.com搬运于
2025-08-24 22:45:03,当前版本为作者最后更新于2018-04-07 16:10:47,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
[yLOI2023] B 苦竹林
Description
给定一个数列 ,找到最小的 ,使得 存在一个长度为 的子数列(可以不连续),满足对任何的 ,都有 。
,。
Analysis
算法一
当 时,只要找到数列里差值最小的两个数;当 时,只要找到数列里最大值与最小值的差。分别可得 分。
算法二
枚举所有选 的方案。一共有 种方案,枚举方案可以搜索,也可以二进制枚举。对每种方案,对应的 就是该方案里 的最大值减去最小值,可以 算出。总时间复杂度 。期望得分 分。
算法三
当 有序时,容易发现答案对应的 数列一定是数列里一个连续的子段。因为答案一定是 数列里最大值减去最小值,而与中间的数无关。所以所选的数应该越紧凑越好。对一个确定的 数列最小值,如果所选的数中间有空隙,则会令最大值有增大的可能,导致答案遍劣。
于是 枚举 里每个长度为 的子区间,当区间左端点为 时,区间最小值就是 ,最大值是 。可以 算出此时的 并与当前算出的答案作比较。
时间复杂度 ,期望得分 分。
算法四
注意到 的顺序其实并不影响答案。因为我们考虑的是 里每一对数,而并不考虑他们之间的前后关系。
于是当 无序时,把 排个序按照算法三完成即可。
如果没有认识到区间最大值就是右端点,区间最小值就是左端点,求最值可以 扫一遍区间。时间复杂度 ,期望得分 分。
如果会 求最值,且使用冒泡排序、插入排序等 的排序,算法的时间复杂度为 ,期望得分 分;如果采用
std::sort等时间复杂度为 的排序,则算法的时间复杂度为 ,期望得分 分。Code
#include <climits> #include <vector> #include <iostream> #include <algorithm> int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int n, m; std::cin >> n >> m; std::vector<int> a(n); std::generate(a.begin(), a.end(), []() { int x; std::cin >> x; return x; }); int ans = INT_MAX; std::sort(a.begin(), a.end()); for (int l = 0, r = m - 1; r < n; ++l, ++r) { ans = std::min(ans, a[r] - a[l]); } std::cout << ans << std::endl; }Generator
void makedata(int T) { int n = 100000, m, lim = 1000000000; if (T <= 4) n = 5; else if (T <= 8) n = 1000; if (T == 1) m = 2; else if (T == 2) m = n; else m = modx(n) + 1; std::vector<int> a(n); std::generate(a.begin(), a.end(), [&]() { return modx(lim) + 1; }); if (T <= 6) std::sort(a.begin(), a.end()); printf("%d %d\n", n, m); for (int i = 0; i < n; ++i) printf("%d%c", a[i], " \n"[i == n-1]); }
- 1
信息
- ID
- 8286
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 2
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者