Codeforces Round #812 (Div. 2)

咕。

B. Optimal Reduction

观察可得:对于所有\(b\),其中要求操作次数最少的为\(\max \{ a \}\).

然后就是看\(f(a)\)是不是等于\(\max \{ a \}\)了,这个只需要满足\(a\)是单峰的就行。

AC代码
// Problem: B. Optimal Reduction
// Contest: Codeforces - Codeforces Round #812 (Div. 2)
// URL: https://codeforces.com/contest/1713/problem/B
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

#define CPPIO std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
#define freep(p) p ? delete p, p = nullptr, void(1) : void(0)

#ifdef BACKLIGHT
#include "debug.h"
#else
#define logd(...) ;
#endif

using i64 = int64_t;
using u64 = uint64_t;

void solve_case(int Case);

int main(int argc, char* argv[]) {
  CPPIO;
  int T = 1;
  std::cin >> T;
  for (int t = 1; t <= T; ++t) {
    solve_case(t);
  }
  return 0;
}

void solve_case(int Case) {
  int n;
  std::cin >> n;
  std::vector<int> a(n + 1);
  for (int i = 1; i <= n; ++i)
    std::cin >> a[i];

  std::vector<int> pma(n + 1);
  for (int i = 1; i <= n; ++i) {
    pma[i] = std::max(pma[i - 1], a[i]);
  }

  std::vector<int> sma(n + 2);
  for (int i = n; i >= 1; --i) {
    sma[i] = std::max(sma[i + 1], a[i]);
  }

  bool flag = true;
  for (int i = 2; i <= n - 1; ++i) {
    if (a[i] < pma[i - 1] && a[i] < sma[i + 1]) {
      flag = false;
    }
  }

  std::cout << (flag ? "YES" : "NO") << "\n";
}

C. Build Permutation

手推了一下,然后猜结论:从n开始往前搞,尽可能构造大的平方数,一定能够得出答案。

AC代码
// Problem: C. Build Permutation
// Contest: Codeforces - Codeforces Round #812 (Div. 2)
// URL: https://codeforces.com/contest/1713/problem/C
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

#define CPPIO std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
#define freep(p) p ? delete p, p = nullptr, void(1) : void(0)

#ifdef BACKLIGHT
#include "debug.h"
#else
#define logd(...) ;
#endif

using i64 = int64_t;
using u64 = uint64_t;

void solve_case(int Case);

int main(int argc, char* argv[]) {
  CPPIO;
  int T = 1;
  std::cin >> T;
  for (int t = 1; t <= T; ++t) {
    solve_case(t);
  }
  return 0;
}

void solve_case(int Case) {
  int n;
  std::cin >> n;

  std::set<int> s;
  for (int i = 0; i < n; ++i) {
    s.insert(i);
  }

  int x = 0;
  while ((x + 1) * (x + 1) <= n + n - 1) {
    x = x + 1;
  }
  logd(x, n);

  std::vector<int> p(n, -1);
  for (int i = n - 1; i >= 0; --i) {
    while (true) {
      if (x < 0) {
        std::cout << "-1\n";
        return;
      }
      int y = x * x - i;
      if (s.count(y)) {
        p[i] = y;
        s.erase(y);
        break;
      } else {
        x = x - 1;
      }
    }
  }

  // for (int i = 0; i < n; ++i) {
  //   int z = int(sqrt(i + p[i]));
  //   assert(z * z == i + p[i]);
  // }

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

D. Tournament Countdown

首先,直接朴素的模拟要\(2^n - 1\)次操作,不可行。

然后,观察发现对于\(4\)个人的比赛,其实只需要2次操作就可以确定胜者,然后就可以自底向上4个为一组搞。这样的话,相当于可以用2次操作干掉3个人,一共要干掉\(2^n - 1\)个人,次数就是\(\lceil (2^n - 1)\frac{2}{3} \rceil = \lfloor \frac{2^{n + 1}}{3} \rfloor\)

AC代码
// Problem: D. Tournament Countdown
// Contest: Codeforces - Codeforces Round #812 (Div. 2)
// URL: https://codeforces.com/contest/1713/problem/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

#define CPPIO std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
#define freep(p) p ? delete p, p = nullptr, void(1) : void(0)

#ifdef BACKLIGHT
#include "debug.h"
#else
#define logd(...) ;
#endif

using i64 = int64_t;
using u64 = uint64_t;

void solve_case(int Case);

int main(int argc, char* argv[]) {
  CPPIO;
  int T = 1;
  std::cin >> T;
  for (int t = 1; t <= T; ++t) {
    solve_case(t);
  }
  return 0;
}

std::mt19937 rng(114514);

void solve_case(int Case) {
  int n;

#ifdef BACKLIGHT
  n = 17;
#else
  std::cin >> n;
#endif

  int limit = ((1 << (n + 1)) + 2) / 3;

#ifdef BACKLIGHT
  std::vector<int> c(1 << n, 0);
  std::vector<int> p(1 << n);
  std::iota(p.begin(), p.end(), 0);

  while (p.size() > 1) {
    std::vector<int> np;
    for (int i = 0; i < p.size(); i += 2) {
      if (rng() & 1) {
        np.push_back(p[i + 1]);
        ++c[p[i + 1]];
      } else {
        np.push_back(p[i]);
        ++c[p[i]];
      }
    }
    p = np;
  }
  int std = p[0];

  int count = 0;
  auto Q = [&c, &count, &limit](int a, int b) -> int {
    ++count;
    assert(count <= limit);

    int r;
    if (c[a] == c[b])
      r = 0;
    else if (c[a] > c[b])
      r = 1;
    else
      r = 2;
    return r;
  };
#else
  int count = 0;
  auto Q = [&count, &limit](int a, int b) -> int {
    ++count;
    assert(count <= limit);
    std::cout << "? " << a + 1 << " " << b + 1 << std::endl;
    int r;
    std::cin >> r;
    return r;
  };
#endif

  std::vector<int> a(1 << n);
  std::iota(a.begin(), a.end(), 0);
  while (a.size() > 1) {
    std::vector<int> na;
    if (a.size() == 2) {
      int r = Q(a[0], a[1]);
      assert(r != 0);
      if (r == 1)
        na.push_back(a[0]);
      else
        na.push_back(a[1]);
    } else {
      for (int i = 0; i < a.size(); i += 4) {
        int r0 = Q(a[i], a[i + 2]);
        if (r0 == 0) {
          int r1 = Q(a[i + 1], a[i + 3]);
          assert(r1 != 0);
          if (r1 == 1) {
            na.push_back(a[i + 1]);
          } else if (r1 == 2) {
            na.push_back(a[i + 3]);
          }
        } else if (r0 == 1) {
          int r1 = Q(a[i], a[i + 3]);
          assert(r1 != 0);
          if (r1 == 1) {
            na.push_back(a[i]);
          } else if (r1 == 2) {
            na.push_back(a[i + 3]);
          }
        } else if (r0 == 2) {
          int r1 = Q(a[i + 1], a[i + 2]);
          assert(r1 != 0);
          if (r1 == 1) {
            na.push_back(a[i + 1]);
          } else if (r1 == 2) {
            na.push_back(a[i + 2]);
          }
        }
      }
    }
    a = na;
  }
  int ans = a[0];

  std::cout << "! " << ans + 1 << std::endl;

#ifdef BACKLIGHT
  logd(std, ans);
  assert(std == ans);
#endif
}

E. Cross Swapping

比赛的时候剩半个小时做这题,没搞出来,甚至思路都完全不对。

对于\(a_{i, j}\),它要么保持不动,要么只能换到\(a_{j, i}\)。然后就可以将矩阵划分成左上角和右下角两个部分,后续只需要考虑左上角。

\(a_{i, j}\)保持不动需要\(k = i\)\(k = j\)这两个操作同时操作,或者同时不操作。换到\(a_{j, i}\)需要只操作\(k = i\)\(k = j\)这两个操作其中一个。对于\(a_{i, j}\),看它和\(a_{j, i}\)的关系,可以判断出\(a_{i, j}\)换到\(a_{j, i}\)上会不会更优。

把每个\(i\)分为两个状态:操作和不操作。如果\(a_{i, j} < a_{j, i}\)的话,就说明\(i\)\(j\)状态不能一样;如果\(a_{i, j} > a_{j, i}\)的话,就说明\(i\)\(j\)状态需要一样。根据这个关系就可以建出图把问题转化成图论问题。现在这个问题有点像2-SAT,只是2-SAT要求不能有冲突,而这个问题出现冲突的时候可以以权重大的优先。

对于建出来的图中的每个连通块,对于其中权重最大的节点\(i\),它是否操作其实都是可行的。因为对于和节点\(i\)对应的操作,以\(a_{i, j}\)换到\(a_{j, i}\)为例,它操作了那么\(j\)不操作就可以,它不操作那么\(j\)操作就可以。这样子,默认连通块中权重最大的节点不操作的话,节点是否操作就可以用带权并查集维护。

AC代码
// Problem: E. Cross Swapping
// Contest: Codeforces - Codeforces Round #812 (Div. 2)
// URL: https://codeforces.com/contest/1713/problem/E
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

#define CPPIO std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
#define freep(p) p ? delete p, p = nullptr, void(1) : void(0)

#ifdef BACKLIGHT
#include "debug.h"
#else
#define logd(...) ;
#endif

using i64 = int64_t;
using u64 = uint64_t;

void solve_case(int Case);

int main(int argc, char* argv[]) {
  CPPIO;
  int T = 1;
  std::cin >> T;
  for (int t = 1; t <= T; ++t) {
    solve_case(t);
  }
  return 0;
}

class WDSU {
 public:
  WDSU(int n) : n_(n), f_(n_), type_(n_) {
    for (int i = 0; i < n_; ++i) {
      f_[i] = i;
      type_[i] = 0;
    }
  }

  int find(int x) {
    if (x != f_[x]) {
      int fx = f_[x];
      int ffx = find(fx);

      f_[x] = ffx;
      type_[x] = type_[x] ^ type_[fx];
    }
    return f_[x];
  }

  void merge(int x, int y, int z) {
    int fx = find(x), fy = find(y);
    if (fx == fy)
      return;

    f_[fy] = fx;
    type_[fy] = type_[x] ^ type_[y] ^ z;
  }

  int type(int x) {
    int fx = find(x);
    return type_[x];
  }

 private:
  int n_;
  std::vector<int> f_;
  std::vector<int> type_;
};

void solve_case(int Case) {
  int n;
  std::cin >> n;

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

  WDSU d(n);
  for (int i = 0; i < n; ++i) {
    for (int j = i + 1; j < n; ++j) {
      if (a[i][j] < a[j][i]) {
        d.merge(i, j, 0);
      }
      if (a[i][j] > a[j][i]) {
        d.merge(i, j, 1);
      }
    }
  }
  for (int i = 0; i < n; ++i) {
    if (d.type(i) == 1) {
      for (int j = 0; j < n; ++j)
        std::swap(a[i][j], a[j][i]);
    }
  }

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

F. Lost Array

To be solved.

posted @ 2022-08-11 18:13  _Backl1ght  阅读(29)  评论(0编辑  收藏  举报