返回

Codeforces:解题思路,B. Getting Zero**

见解分享

题意简述

在 Codeforces 的 B. Getting Zero 题中,你有一个由 n 个整数组成的数组 a。你的目标是通过以下操作将数组 a 中所有元素之和变为 0:

  • 选择一个索引 i(1 ≤ i ≤ n),将 a[i] 变为 -a[i]。
  • 选择两个索引 i 和 j(1 ≤ i < j ≤ n),将 a[i] 和 a[j] 替换为 a[i] - a[j] 和 a[j] + a[i]。

你的任务是确定是否能通过一系列操作将数组 a 的元素之和变为 0,以及提供一组操作序列。

证明

我们先来证明是否能将数组 a 的元素之和变为 0。显然,如果数组 a 中所有元素都为 0,那么我们已经达到目标。否则,数组 a 中一定存在正数和负数。

设数组 a 中正数的和为 s1,负数的和为 s2。如果 s1 = s2,那么我们可以通过将所有正数变为负数,所有负数变为正数来达到目标。

如果 s1 ≠ s2,那么我们可以通过以下操作将 s1 和 s2 之差变为 0:

  • 如果 s1 > s2,选择一个正数 a[i],将其变为 -a[i]。
  • 如果 s1 < s2,选择一个负数 a[i],将其变为 -a[i]。

通过上述操作,我们可以逐步缩小 s1 和 s2 之差,最终使它们相等。此时,我们再将所有正数变为负数,所有负数变为正数,就可以达到目标。

算法

根据上述证明,我们可以设计出以下算法来解决 B. Getting Zero 题:

  1. 计算数组 a 中正数的和 s1 和负数的和 s2。
  2. 如果 s1 = s2,则输出 "YES",并输出将所有正数变为负数,所有负数变为正数的操作序列。
  3. 如果 s1 ≠ s2,则执行以下操作,直到 s1 = s2:
    • 如果 s1 > s2,选择一个正数 a[i],将其变为 -a[i],并输出该操作。
    • 如果 s1 < s2,选择一个负数 a[i],将其变为 -a[i],并输出该操作。
  4. 将所有正数变为负数,所有负数变为正数,并输出该操作。

代码实现

#include <iostream>
#include <vector>

using namespace std;

int main() {
  int n;
  cin >> n;

  vector<int> a(n);
  for (int i = 0; i < n; i++) {
    cin >> a[i];
  }

  int s1 = 0, s2 = 0;
  for (int i = 0; i < n; i++) {
    if (a[i] > 0) {
      s1 += a[i];
    } else {
      s2 += a[i];
    }
  }

  if (s1 == s2) {
    cout << "YES" << endl;
    for (int i = 0; i < n; i++) {
      cout << (a[i] > 0 ? "- " : "+ ") << abs(a[i]) << endl;
    }
  } else {
    vector<pair<int, int>> operations;

    while (s1 != s2) {
      if (s1 > s2) {
        for (int i = 0; i < n; i++) {
          if (a[i] > 0) {
            a[i] = -a[i];
            s1 -= 2 * a[i];
            operations.push_back({i + 1, -a[i]});
            break;
          }
        }
      } else {
        for (int i = 0; i < n; i++) {
          if (a[i] < 0) {
            a[i] = -a[i];
            s2 -= 2 * a[i];
            operations.push_back({i + 1, -a[i]});
            break;
          }
        }
      }
    }

    cout << "YES" << endl;
    for (auto& operation : operations) {
      cout << operation.first << " " << operation.second << endl;
    }
    for (int i = 0; i < n; i++) {
      cout << (a[i] > 0 ? "- " : "+ ") << abs(a[i]) << endl;
    }
  }

  return 0;
}

复杂度分析

  • 时间复杂度:O(n),其中 n 为数组 a 的长度。
  • 空间复杂度:O(n),其中 n 为数组 a 的长度。

总结

通过本文,我们详细阐述了 Codeforces 上的 B. Getting Zero 题目的解题思路,并给出了基于该思路的算法和代码实现。我们还证明了该算法的正确性,并对算法的复杂度进行了分析。

理解本文中的解题思路和算法对于解决类似问题非常有帮助。通过练习和积累,算法竞赛选手可以逐步提升自己的解题能力,在竞赛中取得更好的成绩。