Codeforces Round 960 (Div. 2)

写在前面

比赛地址:https://codeforces.com/contest/1990

依旧是红温温温温温温温温温温场。

AB 每题都吃了两发,爽!D 到最后也没调出来赛后五分钟看出来哪挂了,爽!又要掉一百分了,爽!

所有错误都是每题多看两眼就能找到的但就是没多看两眼。

妈的傻逼一天天的在这干啥啊、、、急成这个逼样子还是急着投胎算了。

A

手玩。

操作等价于选择某个权值的第一个数,并将在此之前所有数全部删除。

先考虑只有一种权值的情况。显然此时若 \(n\) 为奇数,则先手必胜,否则先手必败。

然后考虑多种权值。发现若所有权值的出现次数均为偶数,则先手必败,否则先手仅需选择最大的出现次数为奇数的权值,即可令后手进入必败状态。

于是仅需检查是否有一种权值出现次数为奇数即可。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
//=============================================================
//=============================================================
//=============================================================
int main() {
  //freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;
  while (T --) {
    int n; std::cin >> n;
    int cnt[100] = {0}; 
    for (int i = 1; i <= n; ++ i) {
      int a; std::cin >> a;
      ++ cnt[a];
    }

    int flag = 0;
    for (int i = n; i; -- i) {
      if (cnt[i] % 2 == 1) flag = 1;
    }
    std::cout << (flag ? "YES\n" : "NO\n");
  }
  return 0;
}

B

构造。

显然应令 \([y, x]\) 内全部为 1,\(y - 1, x + 1\) 均为 -1。然后考虑令 \([1, y - 1]\)\([x + 1, n]\) 的前后缀和均尽可能地小以符合题意。

发现仅需从 \(y - 1, x + 1\) 开始,分别向左右构造成 -1/1 交替的形式即可。此时 \([1, y - 1]\)\([x + 1, n]\) 的任意前后缀和均不大于 1。且若 \([1, y - 1]\) 存在前缀和为 1 则 \([1, y-1]\) 和为 0;若 \([x+1, n]\) 存在后缀和为 1 则 \([x+1, n]\) 和为 0。而在 \([y, x]\) 内至少会获得 +2 的贡献,则上述构造一定合法。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 1e5 + 10;
//=============================================================
int n, x, y, ans[kN];
//=============================================================
//=============================================================
int main() {
  //freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;
  while (T --) {
    std::cin >> n >> x >> y;
    // int a = x - 1, b = y - x - 1, c = n - x;
    ans[x] = ans[y] = 1;
    for (int i = y; i <= x; ++ i) ans[i] = 1;
    for (int i = y - 1, j = -1; i; -- i, j = -j) ans[i] = j;
    for (int i = x + 1, j = -1; i <= n; ++ i, j = -j) ans[i] = j;

    for (int i = 1; i <= n; ++ i) std::cout << ans[i] << " ";
    std::cout << "\n";
  }
  return 0;
}

C

模拟,暴力。

先手玩一下。前两次操作没什么规律,但发现从第二次操作开始,数列一定为单调递增,且除了最大的权值外每种权值至少出现 2 次,且每次操作对数列的影响均为使数列整体右移一位,删去最后一个数并在前面补 0。

于是先暴力模拟两轮记录贡献和,然后求得每种权值的出现次数,再降序枚举每种权值(也即每轮删数的顺序),统计删去该权值的各轮的贡献之和即可。

总时间复杂度 \(O(n)\) 级别。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
//=============================================================
int n, a[kN], cnt[kN];
LL ans;
//=============================================================
void solve() {
  for (int i = 0; i <= n; ++ i) cnt[i] = 0;

  int mad = 0;
  for (int i = 1; i <= n; ++ i) {
    ans += a[i];

    ++ cnt[a[i]];
    if (cnt[a[i]] >= 2 && a[i] > mad) mad = a[i];
    a[i] = mad;
  }
}

LL sum(int L_, int R_) {
  return 1ll * (L_ + R_) * (R_ - L_ + 1ll) / 2ll;
}
void solve1() {
  LL delta = 0;
  for (int i = 0; i <= n; ++ i) cnt[i] = 0;
  for (int i = 1; i <= n; ++ i) delta += a[i], ++ cnt[a[i]];

  for (int i = n; i; -- i) {
    if (cnt[i] == 0) continue;
    ans += 1ll * cnt[i] * delta - sum(1, cnt[i] - 1) * i;
    delta -= 1ll * cnt[i] * i;
  }
}
//=============================================================
int main() {
  // freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;
  while (T --) {
    std::cin >> n;
    ans = cnt[0] = 0;
    for (int i = 1; i <= n; ++ i) {
      std::cin >> a[i];
      cnt[i] = 0;
    }
    solve();
    solve();
    solve1();
    std::cout << ans << "\n";
  }
  return 0;
}
/*
1
3
2 2 3
*/

D

手玩,贪心。

发现使用 \(2\times 2\) 矩阵的操作 1 大部分情况下是不值的,对某两行使用两次操作 1 一定不优于两次操作 2。

手玩下可以发现如下结论:

  1. 使用一次操作 2 等于对下方所有行消除之前进行的操作 1 的影响,于是仅需考虑每次连续使用操作 1 的影响。
  2. 使用操作 1 被覆盖的行黑色数量一定不会大于 4,否则不优。
  3. 连续使用操作 1 时,若使用了 \(k\) 次则一定会使 \(k+1\) 行被全部覆盖,否则不优。
  4. 连续使用操作 1 时,被覆盖的第一行黑色数量一定不会大于 2,否则不优。
  5. 由结论 1234,连续使用操作 1 时,第一次操作 1 覆盖的范围一定是 \((x, 1), (x, 2)\),第二次一定是 \((x+1, 3), (x+1, 4)\),第三次一定是 \((x+2, 1), (x+2, 2)\),……直至第 \(x+k\) 行黑色数量大于 4,或使用操作 1 后无法覆盖到第 \(x+k+1\) 行,此时对第 \(x+k\) 行进行一次操作 2 一定不会更劣。然后从第 \(x+k+1\) 行开始重复上述过程。

根据结论 45,仅需从第一行开始贪心地操作即可。若某行满足进行第一次操作 1 的条件,则连续进行操作 1 直至不满足条件,再换用一次操作 2,再从下一行开始重复上述过程。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
//=============================================================
int n, a[kN];
//=============================================================
int solve(int now_, int left_, int right_) {
  if (now_ > n) return 0;

  if (a[now_] <= 0) return solve(now_ + 1, 0, 0); //此行不需操作
  if (a[now_] <= 2) {
    if (left_) return solve(now_ + 1, 0, 0); //左侧两个已被覆盖,则不需操作此行
    return solve(now_ + 1, 1, 0) + 1; //对此行进行操作 1,不会更劣
  }
  if (a[now_] <= 4) {
    if (right_) return solve(now_ + 1, 1, 0) + 1; //右侧两个已被覆盖,对左侧操作
    if (left_) return solve(now_ + 1, 0, 1) + 1; //左侧两个已被覆盖,对右侧操作
    //若无覆盖,对此行操作 2,不会更劣。
  }
  return solve(now_ + 1, 0, 0) + 1; //此行操作 2
}
//=============================================================
int main() {
  // freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;
  while (T --) {
    std::cin >> n;
    for (int i = 1; i <= n; ++ i) std::cin >> a[i];
    std::cout << solve(1, 0, 0) << "\n";
  }
  return 0;
}
/*
1
4
3 2 1 0

1
4
2 4 4 2

1
3
2 3 5

1
6
2 4 4 4 4 2
*/

E

交互,

写在最后

学到了什么:

  • 急你马呢
  • 急你马呢急你马呢
  • 急你马呢急你马呢急你马呢
  • 急你马呢急你马呢急你马呢急你马呢
  • 急你马呢急你马呢急你马呢急你马呢急你马呢
  • 急你马呢急你马呢急你马呢急你马呢急你马呢急你马呢
  • 急你马呢急你马呢急你马呢急你马呢急你马呢急你马呢急你马呢

我操不想活了。

posted @ 2024-07-21 02:03  Luckyblock  阅读(534)  评论(0编辑  收藏  举报