Atcoder Grand Contest 025 简要题解

Digits Sum

暴力。

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

inline int S(int x) {
  int r = 0;
  while (x) {
    r += x % 10, x /= 10;
  }
  return r;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  int n;
  Read(n);
  int ans = INT_MAX;
  for (int i = 1; i < n; ++i) {
    CheckMin(ans, S(i) + S(n - i));
  }
  printf("%d\n", ans);
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

RGB Coloring

暴力。

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 300005;
const int mod = 998244353;

int n, a, b, fac[N], inv[N];
LL k;

inline int C(int x, int y) {
  return 1LL * fac[x] * inv[y] % mod * inv[x - y] % mod;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n), Read(a), Read(b), Read(k);
  fac[0] = fac[1] = inv[0] = inv[1] = 1;
  for (int i = 2; i <= n; ++i) {
    fac[i] = 1LL * fac[i - 1] * i % mod;
    inv[i] = 1LL * (mod - mod / i) * inv[mod % i] % mod;
  }
  for (int i = 2; i <= n; ++i) {
    inv[i] = 1LL * inv[i - 1] * inv[i] % mod;
  }
  int ans = 0;
  for (int i = 0; i <= n && k >= 0; ++i, k -= a) {
    if (k % b == 0) {
      LL t = k / b;
      if (t >= 0 && t <= n) {
        ans = (1LL * C(n, i) * C(n, t) + ans) % mod;
      }
    }
  }
  printf("%d\n", ans);
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Interval Game

不难发现一定是一左一右地跳,如果往左贡献是 2 R i ,往右贡献是 2 L i ,贪心即可。

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 100005;

int n, l[N], p[N], q[N], r[N];
bool v[N];

inline int Move(int &x, LL &a, int l, int r) {
  if (x < l) {
    a += l - x, x = l;
  } else if (x > r) {
    a += x - r, x = r;
  }
}

LL Solve() {
  for (int i = 1; i <= n; ++i) {
    p[i] = q[i] = i, v[i] = false;
  }
  sort(p + 1, p + n + 1, [&](const int &x, const int &y) {
    return l[x] > l[y];
  });
  sort(q + 1, q + n + 1, [&](const int &x, const int &y) {
    return r[x] < r[y];
  });
  int cur = 0;
  LL ret = 0;
  for (int t = 1, i = 1, j = 1; t <= n; ++t) {
    if (t & 1) {
      while (v[p[i]]) {
        ++i;
      }
      Move(cur, ret, l[p[i]], r[p[i]]);
      v[p[i]] = true;
    } else {
      while (v[q[j]]) {
        ++j;
      }
      Move(cur, ret, l[q[j]], r[q[j]]);
      v[q[j]] = true;
    }
  }
  ret += abs(cur);
  return ret;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n);
  for (int i = 1; i <= n; ++i) {
    Read(l[i]), Read(r[i]);
  }
  LL ans = Solve();
  for (int i = 1; i <= n; ++i) {
    l[i] = -l[i], r[i] = -r[i], swap(l[i], r[i]);
  }
  ans = max(ans, Solve());
  printf("%lld\n", ans);
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Choosing Points

如果只考虑一个 D 的限制,那么矛盾的东西构成了一个二分图,因为只要求保留点数 1 4 ,所以每次保留二分图点数较多的那边就可以了。

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 605;

int n, p, q, col[N][N], ans[N][N];
vector <pii> trs;
bool vis[N][N];

inline void DFS(int x, int y) {
  for (auto e : trs) {
    int p = x + e.X, q = y + e.Y;
    if (p >= 0 && p < n << 1 && q >= 0 && q < n << 1) {
      if (!~col[p][q] && !vis[p][q]) {
        col[p][q] = !col[x][y], DFS(p, q);
      }
    }
  }
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n), Read(p), Read(q);
  trs.clear();
  for (int i = 0; i * i <= p; ++i) {
    int x = p - i * i, y = sqrt(x);
    if (y * y == x) {
      trs.pb(mp(i, y));
      trs.pb(mp(-i, y));
      trs.pb(mp(i, -y));
      trs.pb(mp(-i, -y));
    }
  }
  memset(col, -1, sizeof col);
  for (int i = 0; i < n << 1; ++i) {
    for (int j = 0; j < n << 1; ++j) {
      if (!~col[i][j]) {
        col[i][j] = 0, DFS(i, j);
      }
    }
  }
  int cnt = 0;
  for (int i = 0; i < n << 1; ++i) {
    for (int j = 0; j < n << 1; ++j) {
      if (!col[i][j]) {
        ++cnt;
      }
    }
  }
  if (cnt << 1 < n * n) {
    for (int i = 0; i < n << 1; ++i) {
      for (int j = 0; j < n << 1; ++j) {
        col[i][j] = !col[i][j];
      }
    }
  }
  for (int i = 0; i < n << 1; ++i) {
    for (int j = 0; j < n << 1; ++j) {
      if (col[i][j]) {
        vis[i][j] = true;
      }
    }
  }
  trs.clear();
  for (int i = 0; i * i <= q; ++i) {
    int x = q - i * i, y = sqrt(x);
    if (y * y == x) {
      trs.pb(mp(i, y));
      trs.pb(mp(-i, y));
      trs.pb(mp(i, -y));
      trs.pb(mp(-i, -y));
    }
  }
  memset(col, -1, sizeof col);
  for (int i = 0; i < n << 1; ++i) {
    for (int j = 0; j < n << 1; ++j) {
      if (!~col[i][j] && !vis[i][j]) {
        col[i][j] = 0, DFS(i, j);
      }
    }
  }
  cnt = 0;
  for (int i = 0; i < n << 1; ++i) {
    for (int j = 0; j < n << 1; ++j) {
      if (!col[i][j] && !vis[i][j]) {
        ++cnt;
      }
    }
  }
  if (cnt < n * n) {
    for (int i = 0; i < n << 1; ++i) {
      for (int j = 0; j < n << 1; ++j) {
        col[i][j] = !col[i][j];
      }
    }
  }
  int lim = n * n;
  for (int i = 0; i < n << 1; ++i) {
    for (int j = 0; j < n << 1; ++j) {
      if (!col[i][j] && !vis[i][j]) {
        printf("%d %d\n", i, j);
        --lim;
        if (!lim) {
          return 0;
        }
      }
    }
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Walking on a Tree

答案上界是至少被经过一次的边数加上至少被经过两次的边数,可以通过构造证明这个上界。具体地,对 n 归纳,每次删去一个叶子 x ,考虑叶子连出去的边被经过次数,如果是 0 次或者 1 次可以不用管它,否则随便取两条路径 ( x , y ) ( x , z ) ,连一条新的路径 ( y , z ) ,它们的方向只与 ( y , z ) 的方向有关。按照这个暴力构造就可以了。

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 4005;

int n, m, p, ans, s[N], t[N], deg[N], dep[N], par[N], dis[N][N], vis[N][N];
vector <int> adj[N], pth[N];
bool del[N], ers[N], rev[N];
vector <pii> bel[N];

inline void DFS(int x) {
  for (auto y : adj[x]) {
    if (y != par[x]) {
      par[y] = x, dep[y] = dep[x] + 1, DFS(y);
    }
  }
}

inline int Dis(int x, int y) {
  if (x == y) {
    return 0;
  }
  if (dis[x][y]) {
    return dis[x][y];
  }
  if (dep[x] >= dep[y]) {
    return dis[x][y] = Dis(par[x], y) + 1;
  } else {
    return dis[x][y] = Dis(x, par[y]) + 1;
  }
}

inline void Add(int i, int x, int y) {
  if (x == y) {
    return ;
  }
  s[i] = x, t[i] = y;
  vector <int> l, r;
  int u = x, v = y;
  while (u != v) {
    if (dep[u] >= dep[v]) {
      l.pb(u), u = par[u];
    } else {
      r.pb(v), v = par[v];
    }
  }
  reverse(r.begin(), r.end());
  for (auto p : l) {
    pth[i].pb(p);
  }
  pth[i].pb(u);
  for (auto p : r) {
    pth[i].pb(p);
  }
  for (int j = 0; j < pth[i].size(); ++j) {
    bel[pth[i][j]].pb(mp(i, j));
    if (j < pth[i].size() - 1) {
      u = pth[i][j], v = pth[i][j + 1];
      if (u > v) {
        swap(u, v);
      }
      if (vis[u][v] < 2) {
        ++vis[u][v], ++ans;
      }
    }
  }
}

inline bool Go(int i, int j, int x) {
  return (j < pth[i].size() - 1 && pth[i][j + 1] == x) || (j && pth[i][j - 1] == x);
}

inline int Get(int i, int j, int x) {
  return j < pth[i].size() - 1 && pth[i][j + 1] == x ? pth[i].back() : pth[i][0];
}

inline void Make(int i, int x, int y) {
  if (rev[i]) {
    swap(x, y);
  }
  if (Dis(s[i], x) + Dis(y, t[i]) + 1 != Dis(s[i], t[i])) {
    rev[i] = !rev[i];
  }
}

inline void Solve() {
  int x = 0;
  for (int i = 1; i <= n; ++i) {
    if (!ers[i] && deg[i] == 1) {
      x = i;
    }
  }
  if (!x) {
    return ;
  }
  int y = 0;
  for (auto p : adj[x]) {
    if (!ers[p]) {
      y = p;
    }
  }
  ers[x] = true, --deg[y];
  pii a = mp(0, 0), b = mp(0, 0);
  for (auto p : bel[x]) {
    if (!del[p.X] && Go(p.X, p.Y, y)) {
      if (a.X) {
        b = p;
      } else {
        a = p;
      }
    }
  }
  if (!b.X) {
    Solve();
  } else {
    Make(a.X, y, x), Make(b.X, x, y);
    Add(++p, Get(a.X, a.Y, y), Get(b.X, b.Y, y));
    del[a.X] = del[b.X] = true;
    int q = p;
    Solve();
    rev[a.X] ^= rev[q], rev[b.X] ^= rev[q];
  }
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n), Read(m);
  for (int i = 1, x, y; i < n; ++i) {
    Read(x), Read(y);
    adj[x].pb(y), adj[y].pb(x);
    ++deg[x], ++deg[y];
  }
  DFS(1);
  for (int i = 1, x, y; i <= m; ++i) {
    Read(x), Read(y);
    Add(++p, x, y);
  }
  printf("%d\n", ans);
  Solve();
  for (int i = 1; i <= m; ++i) {
    if (rev[i]) {
      printf("%d %d\n", t[i], s[i]);
    } else {
      printf("%d %d\n", s[i], t[i]);
    }
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Addition and Andition

从高位到低位一位一位模拟做 k 遍的过程,碰到 ( 0 , 1 ) ( 1 , 0 ) 直接暴力,不然碰到一段连续的 ( 0 , 0 ) 可以一起做。因为低位的影响不会超过高位,所以不会碰到 ( 1 , 1 ) 。复杂度均摊下来是线性,拿个栈维护一下就行了。

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 1000005;
const int inf = 0x3f3f3f3f;

stack <pair <int, pii>> cur, tmp;
char s[N], t[N];
int n, m, k;

inline void Push(stack <pair <int, pii>> &s, int x, pii p) {
  if (!s.empty() && s.top().Y == p) {
    s.top().X += x;
  } else {
    s.push(mp(x, p));
  }
}

inline void Pop(stack <pair <int, pii>> &s, int x) {
  if (s.top().X == x) {
    s.pop();
  } else {
    s.top().X -= x;
  }
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n), Read(m), Read(k);
  int p = max(n, m);
  scanf("%s%s", s + 1, t + 1);
  reverse(s + 1, s + n + 1);
  reverse(t + 1, t + m + 1);
  for (int i = 1; i <= n; ++i) {
    s[i] -= '0';
  }
  for (int i = 1; i <= m; ++i) {
    t[i] -= '0';
  }
  Push(cur, inf, mp(0, 0));
  for (int i = p; i; --i) {
    if (s[i] && t[i]) {
      int z = k;
      bool f = true;
      while (z) {
        int x = cur.top().Y.X, y = cur.top().Y.Y;
        if (x) {
          Push(tmp, 1, mp(0, 0));
          Push(tmp, 1, mp(0, 1));
          Pop(cur, 1);
          x = cur.top().Y.X, y = cur.top().Y.Y;
          if (x) {
            Push(tmp, cur.top().X, mp(0, 0));
            Pop(cur, cur.top().X);
            x = cur.top().Y.X, y = cur.top().Y.Y;
          }
          Pop(cur, 1);
          if (y) {
            --z;
          } else {
            Push(tmp, 1, mp(1, 0));
            f = false;
            break;
          }
        } else if (y) {
          Push(tmp, 1, mp(0, 0));
          Push(tmp, 1, mp(1, 0));
          Pop(cur, 1);
          x = cur.top().Y.X, y = cur.top().Y.Y;
          if (y) {
            Push(tmp, cur.top().X, mp(0, 0));
            Pop(cur, cur.top().X);
            x = cur.top().Y.X, y = cur.top().Y.Y;
          }
          Pop(cur, 1);
          if (x) {
            --z;
          } else {
            Push(tmp, 1, mp(0, 1));
            f = false;
            break;
          }
        } else {
          int t = min(cur.top().X, z);
          Push(tmp, t, mp(0, 0));
          Pop(cur, t);
          z -= t;
        }
      }
      if (f) {
        Push(cur, 1, mp(1, 1));
      }
      while (!tmp.empty()) {
        Push(cur, tmp.top().X, tmp.top().Y);
        tmp.pop();
      }
    } else {
      Push(cur, 1, mp(s[i], t[i]));
    }
  }
  vector <pair <int, pii>> v;
  while (!cur.empty()) {
    v.pb(cur.top()), cur.pop();
  }
  reverse(v.begin(), v.end());
  for (int i = 0; i < v.size(); ++i) {
    if (v[i].Y.X) {
      for (int j = i; j < v.size(); ++j) {
        for (int k = 0; k < v[j].X; ++k) {
          putchar(v[j].Y.X + '0');
        }
      }
      putchar(10);
      break;
    }
  }
  for (int i = 0; i < v.size(); ++i) {
    if (v[i].Y.Y) {
      for (int j = i; j < v.size(); ++j) {
        for (int k = 0; k < v[j].X; ++k) {
          putchar(v[j].Y.Y + '0');
        }
      }
      putchar(10);
      break;
    }
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

猜你喜欢

转载自blog.csdn.net/wxh010910/article/details/80654929