2022.10.08 总结
1. 洛谷 P8092
题意
有一个序列 \(a\),每次操作选择两个相邻元素 \(a_i, a_{i + 1}\),并将它们的值 \(-1\),这样一次操作在答案中算作两次,请你求出最少需要多少次才能使得序列 \(a\) 中的所有元素相等。
思路
48 分
枚举最终元素,暴力修改序列,判断最后两个元素是否相等。
时间复杂度
枚举最终元素,\(O(\max(h_i))\)。
更改序列,\(O(n)\)。
总时间复杂度为 \(O(\max(h_i) \times n)\)。
空间复杂度
临时数组更改序列,\(O(n)\)。
100 分
从头到尾将序列修改成一个非递增序列,再从后往前将序列维护成元素全部相等,最后再判断一次元素是否相等。
时间复杂度
序列总共遍历 \(3\) 次,\(O(3 \times n)\)。
总共 \(t\) 组数据,总时间复杂度为 \(O(t \times n)\)。
空间复杂度
用数组模拟更改序列,\(O(n)\)。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int t, n, h[N];
int main(){
cin >> t;
while (t--) {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> h[i];
}
long long cnt = 0;
bool f = 0;
for (int i = 2; i < n; i++) { // 从前往后遍历
if (h[i] < h[i - 1]) {
continue;
}
cnt += 2 * (h[i] - h[i - 1]);
h[i + 1] -= h[i] - h[i - 1], h[i] = h[i - 1]; // 更改序列
if (h[i] < 0 || h[i + 1] < 0) {
f = 1;
break;
}
}
for (int i = n - 1; i > 1; i--) { // 从后往前遍历
if (h[i] < h[i + 1]) {
continue;
}
cnt += 2 * (h[i] - h[i + 1]);
h[i - 1] -= h[i] - h[i + 1], h[i] = h[i + 1]; // 更改序列
if (h[i] < 0 || h[i - 1] < 0) {
f = 1;
break;
}
}
int p = h[1];
for (int i = 1; i <= n; i++) { // 判断是否相等
if (h[i] != p) {
f = 1;
break;
}
}
if (f) {
cnt = -1;
}
cout << cnt << endl;
}
return 0;
}
2. 洛谷 P8184
题意
有两个序列 \(a, b\),每次可以选择一个 \(a_i\) 并向左移动一些位置,请你求出最少需要多少次可以使得 \(a\) 变成 \(b\)。
思路
70 分
记录下序列 \(b\) 的每个元素的编号,将 \(a\) 序列的元素替换成编号,再进行插入排序,将编号从小到大排序。
时间复杂度
记录编号,\(O(n)\)。
替换成编号,\(O(n)\)。
插入排序,\(O(n \times n)\)。
总时间复杂度为 \(O(n \times n)\)。
空间复杂度
临时数组记录编号,\(O(n)\)。
100 分
双指针,\(a\) 序列一个,\(b\) 序列一个,将元素进行一一对应。
时间复杂度
双指针,\(O(n)\)。
空间复杂度
一个标记数组记录是否出现过,\(O(n)\)。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, a[N], b[N], c, cnt;
bool f[N];
int main(){
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
cin >> b[i];
}
for (int i = 1, j = 1; max(i, j) <= n; ) {
if (f[b[j]]) { // 如果已经被插入到序列中
continue;
}
if (a[i] != b[j]) { // 两个元素不相等
cnt++, f[b[j]] = 1; // 需要插入 b[j],并标记 b[j] 被插入过
j++;
} else {
f[a[i]] = 1; // 这个元素被插入过
while (i <= n && f[a[i]]) { // 往后找到第一个没有被插入过的
i++;
}
j++;
}
}
cout << cnt;
return 0;
}