[模拟] aw3664. 数组补全(模拟+贪心+中位数+思维)
Posted Ypuyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[模拟] aw3664. 数组补全(模拟+贪心+中位数+思维)相关的知识,希望对你有一定的参考价值。
1. 题目来源
链接:3664. 数组补全
2. 题目解析
有点考思维,模拟题。
思路:
- 合法填充后要求数组中位数为
y
,那就意味着小于y
的数的个数有 n 2 \\frac n 2 2n 个,大于等于y
个数的个数有 n 2 + 1 \\frac {n} 2 + 1 2n+1 个。 - 若使总和最小,则填充进来的数应该尽可能小。
- 输入时统计小于
y
的个数和大于等于y
的个数。- 若小于
y
的个数已经大于了n/2
则说明中位数一定不满足要求,则输出 -1。否则应该将小于y
的个数填充至 n 2 \\frac n 2 2n 个,填充数应该选最小,选 1。 - 若大于
y
的个数已经大于n/2+1
,是合法情况…不要进行误判。 若小于n/2+1
的话,应该填充差值个y
,保证总和最小。
- 若小于
- 最后判断一下总和是否小于
x
即可。
贪心的意思,反正每次都加上最小值,所以总和一定是最小的,当最小总和都大于 x
那么一定不存在合法情况!
见名知意,统计小于、小于等于、大于、大于等于的变量命名!
<
\\lt
< lt
≤
\\le
≤ le
>
\\gt
> gt
≥
\\ge
≥ ge
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( 1 ) O(1) O(1)
这种写法有一个坑点,当前 k
个数输入之后,ge
已经大于 n/2+1
了,那么 y
就不打印了,且 1 不应该打印 n/2-lt
个,而是打印 n-k
个即可,即把后面的补满就行了。
如果仍旧打印 n/2-lt
个的话,相当于将严格小于 y
的数的个数强行补充到 n/2
个,但实际上,中位数有重复情况出现。在这 WA
了好几次…
#include <bits/stdc++.h>
using namespace std;
int n, k, p, x, y;
int main() {
scanf("%d%d%d%d%d", &n, &k, &p, &x, &y);
int sum = 0, lt = 0, ge = 0;
for (int i = 0; i < k; i ++ ) {
int t;
scanf("%d", &t);
sum += t; // 统计 k 个和
if (t < y) lt ++ ;
else ge ++ ;
}
int l = n / 2, r = n / 2 + 1;
if (lt > l) {
puts("-1");
return 0;
}
int c1 = 0, cy = 0; // 统计打印 1 打印 y 的次数
if (ge >= r) sum += (n - k) * 1, c1 = n - k; // 坑点,当ge大于r时,补上n-k个1即可,而不是n-lt个1
else sum += (l - lt) * 1 + (r - ge) * y, c1 = l - lt, cy = r - ge; // 补上1,补上y
if (sum > x) puts("-1");
else {
while (c1 -- ) printf("%d ", 1);
while (cy -- ) printf("%d ", y);
}
return 0;
}
mrk
大佬的代码依旧如此简洁!
优先补 1
,强行给 y
找到 n/2
个严格小于等于它的数。如果填充多了,就说明中位数已经满足了,就不用填充 y
了。如果还有空,说明中位数还未满足,则后面的全部填充为 y
即可。
#include <iostream>
#include <cstdio>
#define pb push_back
#define fi first
#define se second
#define mp make_pair
using namespace std;
typedef long long LL;
template <typename T> void chkMax(T &x, T y) { if (y > x) x = y; }
template <typename T> void chkMin(T &x, T y) { if (y < x) x = y; }
const int N = 1e3 + 5;
int n, k, p, x, y, a[N], t;
int main() {
scanf("%d%d%d%d%d", &n, &k, &p, &x, &y);
LL s = 0;
int c = 0;
for (int i = 1; i <= k; i++) {
scanf("%d", a + i);
if (a[i] < y) c++;
}
t = k;
if (c > n / 2) {
puts("-1");
return 0;
}
for (int i = 0; i < n / 2 - c; i++) a[++t] = 1; // 优先补 1
while (t < n) { // 不足补 y
a[++t] = y;
}
for (int i = 1; i <= n; i++) s += a[i];
if (s > x) {
puts("-1");
return 0;
}
for (int i = k + 1; i <= n; i++) printf("%d ", a[i]);
return 0;
}
以上是关于[模拟] aw3664. 数组补全(模拟+贪心+中位数+思维)的主要内容,如果未能解决你的问题,请参考以下文章