#P3418. 第1题-小A删数字
-
1000ms
Tried: 136
Accepted: 33
Difficulty: 5
所属公司 :
百度
时间 :2025年8月19日-研发
-
算法标签>贪心算法
第1题-小A删数字
关键观察
-
设连续三元组为 (x,y,z)。若删除中间元素 y,新的贡献变为 ∣x−z∣。 要想权值不变,必须满足
∣x−y∣+∣y−z∣=∣x−z∣. -
上式等价于
(x≤y≤z)或(x≥y≥z),即 y 处于 [x,z] 区间内部——三点单调(含相等)时,中间点可安全删除。
因此,只需留下:
- 整体最左、最右端点;
- 所有“拐点”(峰值或谷值)。
其余都能删掉。
算法
判断可删条件
对当前栈顶两个元素 sk−1,sk 和读入的新元素 v: 若
(sk−1≤sk≤v)或(sk−1≥ sk≥v),
则 sk 可删;弹栈并继续判断,直到条件不满足或栈不足 2 个。
复杂度
- 时间:每个元素至多入栈、出栈一次,O(n)
- 空间:栈 O(n)(最坏单调波形全保留)
参考代码
C++
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
if (!(cin >> n)) return 0;
long long x; cin >> x; // a1
long long p2 = 0, p1 = x; // p2 无效用 0 占位
int keep = 1; // 已保留数量
for (int i = 2; i <= n; ++i) {
long long v; cin >> v;
if (v == p1) continue; // 相邻相等可删
if (keep >= 2 && ((p2 <= p1 && p1 <= v) || (p2 >= p1 && p1 >= v))) {
// 删除 p1,用 v 覆盖
p1 = v;
} else {
// v 是拐点,需保留
p2 = p1;
p1 = v;
++keep;
}
}
cout << n - keep << '\n';
return 0;
}
Java
import java.io.*;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine().trim());
StringTokenizer st = new StringTokenizer(br.readLine());
long first = Long.parseLong(st.nextToken()); // a1
long p2 = 0, p1 = first; // p2 暂无效
int keep = 1;
for (int i = 2; i <= n; i++) {
long v = Long.parseLong(st.nextToken());
if (v == p1) continue; // 相邻相等
if (keep >= 2 && ((p2 <= p1 && p1 <= v) || (p2 >= p1 && p1 >= v))) {
p1 = v; // 删 p1
} else {
p2 = p1;
p1 = v;
keep++;
}
}
System.out.println(n - keep);
}
}
Python
import sys
n = int(sys.stdin.readline())
a = list(map(int, sys.stdin.readline().split()))
first = a[0]
p2 = None # 倒数第二个保留点
p1 = first # 最新保留点
keep = 1 # 已保留数量
for v in a[1:]:
if v == p1:
continue # 相邻相等可删
if p2 is not None and ((p2 <= p1 <= v) or (p2 >= p1 >= v)):
p1 = v # 删除 p1
else:
p2, p1 = p1, v
keep += 1
print(n - keep)
题目内容
小A有一个长度为 n 的数组 a1,a2,...,an 。
定义数组的权值为 ∣a1−a2,∣+∣a2−a3∣...+∣an−1−an∣,长度为 1 的数组权值为 0 。
现在小A想玩一个删数字的游戏,他想在数组中删去若干个数(不能全部删完),并保证剩下数组的权值不变。
小A想知道在采取最优策略的情况下,他最多可以删掉多少个数字,你可以告诉他吗?
输入描述
第一行一个正整数 n ,表示数字个数。
第二行 n 个正整数,表示 ai 。
1≤n≤105,1≤ai≤109
输出描述
输出一行,一个正整数,表示最多可以删去几个数。
样例1
输入
10
1 2 8 8 9 1 1 1 5 5
输出
6
样例2
输入
5
6 6 6 6 6
输出
4