Loading

2022.10.08 总结

1. 洛谷 P8092

洛谷 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

洛谷 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;
}
posted @ 2023-03-02 22:39  chengning0909  阅读(23)  评论(0编辑  收藏  举报