比赛链接:Here

AB水题,跳过


C - Swappable

在数组中找到满足条件的数对 AtCoder Beginner Contest 206 - 图1#card=math&code=%28i%2Cj%29)

  • AtCoder Beginner Contest 206 - 图2#card=math&code=1%20%5Cle%20i%20%3C%20j%20%20%5Cle%20N%20%28N%5Cin%5B2%2C3e5%5D%29)
  • AtCoder Beginner Contest 206 - 图3

一道经典利用 map 减少搜索规模的题,

先假设每个数互不相同:ans = n * (n - 1) / 2

map 存每个数出现的次数,然后减去相同的情况 ans -= x * (x - 1) / 2

【AC Code】

  1. void solve() {
  2. ll n;
  3. cin >> n;
  4. ll ans = n * (n - 1) / 2;
  5. map<ll, ll>mp;
  6. for (int i = 1; i <= n; ++i) {
  7. ll x; cin >> x;
  8. mp[x]++;
  9. }
  10. for (auto x : mp)
  11. ans -= x.second * (x.second - 1) / 2;
  12. cout << ans;
  13. }

D - KAIBUNsyo

在数组 AtCoder Beginner Contest 206 - 图4 中有 AtCoder Beginner Contest 206 - 图5 个正整数,给定一种操作:

  • 选择 AtCoder Beginner Contest 206 - 图6AtCoder Beginner Contest 206 - 图7 ,将数组中全部 AtCoder Beginner Contest 206 - 图8 替换为 AtCoder Beginner Contest 206 - 图9

请问最少次数是多少可以使得数组$A $ 回文


首先一个重要的点:

  • 对于每一个 AtCoder Beginner Contest 206 - 图10 的数对,最终都会被某一个相同的数替代

让我们将其视为连接无向图中顶点 AtCoder Beginner Contest 206 - 图11 之间的边。

然后,我们可以看到以下事实:

  • 对于每个整数对 AtCoder Beginner Contest 206 - 图12#card=math&code=%28i%2Cj%29) ,如果 AtCoder Beginner Contest 206 - 图13AtCoder Beginner Contest 206 - 图14 属于图的同一个连通分量,则 AtCoder Beginner Contest 206 - 图15AtCoder Beginner Contest 206 - 图16 都应该用相同的整数代替。

现在,我们如何最小化操作次数以使连通分量中的所有整数都相同?

如果一个连通分量有 AtCoder Beginner Contest 206 - 图17 个整数,显然我们需要 AtCoder Beginner Contest 206 - 图18 次或更多次操作才能使它们成为相同的整数。 即目标可以在 AtCoder Beginner Contest 206 - 图19 次替换中实现,如下所述:

在连通分量中固定一个整数,并将连通分量中的所有其他整数更改为固定整数。

因此,该问题的解决方案是(AtCoder Beginner Contest 206 - 图20 中不同整数的数量)-(图的连通分量的数量)。

有几种方法可以找到这个值; 两种典型的方法是:

  • 对每个连接的组件执行 DFS 或 BFS。AtCoder Beginner Contest 206 - 图21#card=math&code=%5Cmathcal%7BO%7D%28N%29)
  • 使用并查集。AtCoder Beginner Contest 206 - 图22#card=math&code=%5Cmathcal%7BO%7D%28N%5C%20log%5C%20N%29)

这里采用 DFS 解决问题

【AC Code】

  1. using G = vector<vector<int>>;
  2. void dfs(int u, vector<bool> &f, G &g) {
  3. if (!f[u]) {return;}
  4. f[u] = false;
  5. for (auto &v : g[u]) dfs(v, f, g);
  6. }
  7. void solve() {
  8. int n; cin >> n;
  9. vector<int>a(n);
  10. vector<bool>f(2e5 + 10, false);
  11. G g(2e5 + 10);
  12. int cnt = 0;
  13. for (auto &x : a) {
  14. cin >> x;
  15. if (!f[x]) {f[x] = true, cnt++;}
  16. }
  17. int p = 0, q = n - 1;
  18. while (p < q) {
  19. g[a[p]].emplace_back(a[q]);
  20. g[a[q]].emplace_back(a[p]);
  21. p++, q--;
  22. }
  23. for (int i = 1; i <= 2e5; ++i)
  24. if (f[i]) { cnt--; dfs(i, f, g); }
  25. cout << cnt << "\n";
  26. }

F - Interval Game 2

Alice 和 Bob 又在玩游戏了,

他们有 AtCoder Beginner Contest 206 - 图23 个半开区间 AtCoder Beginner Contest 206 - 图24#card=math&code=%5BL_i%2CR_i%29) 来进行 Game:

  • Alice 和 Bob 交替进行以下操作,Alice 先行。
    AtCoder Beginner Contest 206 - 图25 个间隔中,选择一个不与任何已选择的间隔相交的间隔。

无法进行操作的玩家失败,其他玩家获胜。

如果两个玩家都以最佳操作,哪个玩家会获胜?


https://drken1215.hatenablog.com/entry/2021/06/19/224100

  1. const int N = 100;
  2. int n;
  3. vector<int>L, R;
  4. vector<vector<int>>dp;
  5. int solve(int l = 0, int r = N) {
  6. if (l == r) return 0;
  7. if (dp[l][r] != -1)return dp[l][r];
  8. set<int>s;
  9. for (int i = 0; i < n; ++i) {
  10. if (l <= L[i] and R[i] <= r) {
  11. int tmp = solve(l, L[i]) ^ solve(R[i], r);
  12. s.insert(tmp);
  13. }
  14. }
  15. int grundy = 0;
  16. while (s.count(grundy)) ++grundy;
  17. return dp[l][r] = grundy;
  18. }
  19. int main() {
  20. cin.tie(nullptr)->sync_with_stdio(false);
  21. int _; for (cin >> _; _--;) {
  22. cin >> n;
  23. L.resize(n), R.resize(n);
  24. for (int i = 0; i < n; ++i) {
  25. cin >> L[i] >> R[i];
  26. L[i]--, R[i]--;
  27. }
  28. dp.assign(N, vector<int>(N + 1, -1));
  29. cout << (solve() > 0 ? "Alice\n" : "Bob\n");
  30. }
  31. }