1516A. Tit for Tat

題意:

給定大小為 Codeforces Round #717 (Div. 2) 个人题解 A~C (A思維,B位運算,C背包DP) - 图1 的數組和可操作次數 Codeforces Round #717 (Div. 2) 个人题解 A~C (A思維,B位運算,C背包DP) - 图2

  • 每次操作都選定兩個數(如果 Codeforces Round #717 (Div. 2) 个人题解 A~C (A思維,B位運算,C背包DP) - 图3 ),使第一個數 - Codeforces Round #717 (Div. 2) 个人题解 A~C (A思維,B位運算,C背包DP) - 图4 ,另一個數 + Codeforces Round #717 (Div. 2) 个人题解 A~C (A思維,B位運算,C背包DP) - 图5

輸出字典序最小的數組

思路:

既然要輸出字典序最小,那麽肯定是選最前面 - 1,最後 + 1

  1. void solve() {
  2. int n, k;
  3. cin >> n >> k;
  4. int a[n + 1];
  5. for (int i = 1; i <= n; ++i) cin >> a[i];
  6. int i = 1, j = n;
  7. while (true) {
  8. if (i == j || k == 0) break;
  9. if (a[i] >= 1) a[i] -= 1, a[j] += 1, k--;
  10. else
  11. i++;
  12. }
  13. for (int i = 1; i <= n; ++i) cout << a[i] << " ";
  14. cout << "\n";
  15. }

1516B. AGAGA XOOORRR

題意:

思路:

我采取的方法是模擬,首先求出全部元素的 XOR 結果,如果 Codeforces Round #717 (Div. 2) 个人题解 A~C (A思維,B位運算,C背包DP) - 图6 則是元素兩兩相等的情況比如:Codeforces Round #717 (Div. 2) 个人题解 A~C (A思維,B位運算,C背包DP) - 图7 此時輸出 YES 即可。

維護 Codeforces Round #717 (Div. 2) 个人题解 A~C (A思維,B位運算,C背包DP) - 图8 如果 Codeforces Round #717 (Div. 2) 个人题解 A~C (A思維,B位運算,C背包DP) - 图9 則説明前面已使用的一段可以 XOR 為同一個值,此時 Codeforces Round #717 (Div. 2) 个人题解 A~C (A思維,B位運算,C背包DP) - 图10

如果最後 cnt > 2 && t == 0 則説明數組完全可以通過 XOR 操作簡化為相同的值

  1. void solve() {
  2. int n;
  3. cin >> n;
  4. vector<int> a(n);
  5. for (int &x : a) cin >> x;
  6. int s = 0;
  7. for (int x : a) s ^= x;
  8. if (s == 0) {
  9. cout << "YES\n";
  10. return;
  11. }
  12. int t = 0, cnt = 0;
  13. for (int i = 0; i < n; ++i) {
  14. t ^= a[i];
  15. if (t == s) cnt++, t = 0;
  16. }
  17. if (cnt > 2 && t == 0) cout << "YES\n";
  18. else
  19. cout << "NO\n";
  20. }

下面代碼為官方 AC 代碼:

  1. void solve() {
  2. int n;
  3. cin >> n;
  4. vector<int> a(n + 1);
  5. for (int i = 1, x; i <= n; ++i) {
  6. cin >> x;
  7. a[i] = a[i - 1] ^ x;
  8. }
  9. bool f = !a[n];
  10. for (int i = 1; i <= n; ++i)
  11. for (int j = i + 1; j <= n; ++j)
  12. f |= (a[i] == (a[j] ^ a[i]) && a[i] == (a[n] ^ a[j]));
  13. cout << (f ? "YES\n" : "NO\n");
  14. }

1516C. Baby Ehab Partitions Again

題意:

將數組劃分為兩個子序列,如果存在兩個子序列之和相等則被稱爲 “好數組” 現在請問是否能刪除幾個元素使得數組不是 “好數組”

思路:

首先,让我们检查一下数组是否已经很好。 这可以通过背包dp完成。 如果是,则答案为0。否则,可以始终删除一个元素以使其良好,这是找到它的方法:由于可以对数组进行分区,因此其总和为偶数。 因此,如果我们删除一个奇数元素,它将是奇数,并且将无法对其进行分区。 如果没有奇数元素,那么所有元素都是偶数。 但是,您可以将所有元素除以2,而无需更改答案。 为什么? 因为将所有内容都除以2后在新数组中进行的分区就是在原始数组中进行的分区,反之亦然。 我们只是重新缩放了一切。 因此,当所有元素都是偶数时,您可以继续除以2,直到其中一个元素变为奇数。 删除它,您就完成了。 如果您想用一句话来解决,请删除可能的最小有效位最小的元素。
另外,出于类似的推理,您可以先将整个数组除以其gcd,然后删除任何奇数元素(因为gcd为1,该元素必须存在)

  1. int dp[200010];
  2. void solve() {
  3. int n;
  4. cin >> n;
  5. vector<int> a(n + 1);
  6. int d = 0;
  7. for (int i = 1; i <= n; ++i) cin >> a[i], d = __gcd(d, a[i]);
  8. for (int i = 1; i <= n; ++i) a[i] /= d;
  9. dp[0] = 1;
  10. int S = 0, id = 0;
  11. for (int i = 1; i <= n; ++i) {
  12. S += a[i];
  13. if (a[i] & 1) id = i;
  14. for (int j = S; j >= a[i]; j--) dp[j] |= dp[j - a[i]];
  15. }
  16. if (S & 1 || dp[S / 2] == 0) cout << "0";
  17. else
  18. cout << "1\n"
  19. << id;
  20. }