Atcoder Grand Contest 024 简要题解

Fairness:

(A,B,C) ( A , B , C ) 经过一次变换之后变成 (B+C,A+C,A+B) ( B + C , A + C , A + B ) 再变换变成 (A+B+C+A,A+B+C+B,A+B+C+C) ( A + B + C + A , A + B + C + B , A + B + C + C )

如果 k k 是偶数答案为 AB A − B 否则是 BA B − A

#include 

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;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  int a, b, c;
  LL k;
  Read(a), Read(b), Read(c), Read(k);
  if (k & 1) {
    printf("%d\n", b - a);
  } else {
    printf("%d\n", a - b);
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Backfront:

将问题倒着做,变成可以将两端的插入到中间,那么贪心保留一个最长上升子串即可。

#include 

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 = 200005;

int n, ans, a[N];

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n), ans = 1;
  for (int i = 1, x; i <= n; ++i) {
    Read(x), a[x] = i;
  }
  for (int i = 1, c = 0; i <= n; ++i) {
    if (a[i] > a[i - 1]) {
      CheckMax(ans, ++c);
    } else {
      c = 1;
    }
  }
  printf("%d\n", n - ans);
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Sequence Growing Easy:

贪心加就行了。

#include 

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 = 200005;

int n, a[N];
LL ans;

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

Isomorphism Freak

假设直径是 D D ,那么答案为 D2 ⌊ D 2 ⌋ 。然后以直径的一个或者两个中点为根,将其他东西填满即可。注意如果直径长度为偶数,可以让直径长度加 1 1 来减小第二问的答案。

#include 

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 = 105;

vector <int> adj[N], seq[N];
int n, dep[N], par[N];
LL ans, f[N], g[N];

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

inline LL Solve(int x) {
  DFS(x, 0);
  int maxdep = 0;
  for (int i = 1; i <= n; ++i) {
    CheckMax(maxdep, dep[i]);
  }
  for (int i = 1; i <= maxdep; ++i) {
    seq[i].clear();
  }
  for (int i = 1; i <= n; ++i) {
    seq[dep[i]].pb(i);
  }
  LL ret = 1;
  for (int i = maxdep - 1; i; --i) {
    int maxson = 0;
    for (auto x : seq[i]) {
      int cnt = 0;
      for (auto y : adj[x]) {
        if (dep[y] == i + 1) {
          ++cnt;
        }
      }
      CheckMax(maxson, cnt);
    }
    ret *= maxson;
  }
  return ret;
}

inline LL Solve(int x, int y) {
  dep[y] = 0, DFS(x, y), dep[x] = 0, DFS(y, x), dep[x] = 1;
  int maxdep = 0;
  for (int i = 1; i <= n; ++i) {
    CheckMax(maxdep, dep[i]);
  }
  for (int i = 1; i <= maxdep; ++i) {
    seq[i].clear();
  }
  for (int i = 1; i <= n; ++i) {
    seq[dep[i]].pb(i);
  }
  LL ret = 1;
  for (int i = maxdep - 1; i; --i) {
    int maxson = 0;
    for (auto x : seq[i]) {
      int cnt = 0;
      for (auto y : adj[x]) {
        if (dep[y] == i + 1) {
          ++cnt;
        }
      }
      CheckMax(maxson, cnt);
    }
    ret *= maxson;
  }
  return ret << 1;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n);
  for (int i = 1, x, y; i < n; ++i) {
    Read(x), Read(y);
    adj[x].pb(y), adj[y].pb(x);
  }
  DFS(1, 0);
  int s = 0;
  for (int i = 1; i <= n; ++i) {
    if (dep[i] > dep[s]) {
      s = i;
    }
  }
  DFS(s, 0);
  int t = 0;
  for (int i = 1; i <= n; ++i) {
    if (dep[i] > dep[t]) {
      t = i;
    }
  }
  if (!(dep[s] + dep[t] & 1)) {
    int mid = dep[s] + dep[t] >> 1, r;
    for (r = t; dep[r] != mid; r = par[r]);
    ans = Solve(r);
    for (auto x : adj[r]) {
      CheckMin(ans, Solve(r, x));
    }
    printf("%d %lld\n", mid, ans);
  } else {
    int mid1 = dep[s] + dep[t] >> 1, mid2 = dep[s] + dep[t] + 1 >> 1, r1, r2;
    for (r1 = t; dep[r1] != mid1; r1 = par[r1]);
    for (r2 = t; dep[r2] != mid2; r2 = par[r2]);
    printf("%d %lld\n", mid1, Solve(r1, r2));
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Sequence Growing Hard

不难发现如果新增的位置与原来这个位置的值相等,那么可以认为填的后面一个位置的值而不是这个位置。将每个填的数向它后面的数连边,那么构成了一棵树,做一个树形DP就行了。

#include 

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 = 305;

int n, m, mod, c[N][N], f[N][N], g[N][N];

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n), Read(m), Read(mod);
  for (int i = 0; i <= n; ++i) {
    c[i][0] = 1;
    for (int j = 1; j <= i; ++j) {
      c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
    }
  }
  for (int i = 1; i <= m; ++i) {
    f[1][i] = g[1][i] = (m - i + 1) % mod;
  }
  for (int i = 2; i <= n; ++i) {
    for (int j = m - 1; j; --j) {
      f[i][j] = (g[i - 1][j + 1] + f[i][j + 1]) % mod;
    }
    for (int j = 1; j <= m; ++j) {
      g[i][j] = f[i][j];
      for (int k = 1; k < i; ++k) {
        g[i][j] = (1LL * f[k][j] * g[i - k][j] % mod * c[i - 1][k - 1] + g[i][j]) % mod;
      }
    }
  }
  printf("%d\n", g[n][1]);
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Simple Subsequence Problem

考虑如何表示一个串的所有子序列,建一个类似子序列自动机的东西,比如 000110101 000110101 可以转移到 0[00110101] 0 [ 00110101 ] 或者 1[10101] 1 [ 10101 ] ,其中 s[t] s [ t ] 表示选了 s s ,要在 t t 中选一个子序列。建出一个DAG之后跑DP即可。

#include 

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 = 1048580;
const int M = 25;

int n, m, len, ans, f[M][N], g[M][N];
char s[N];

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n), Read(m);
  for (int i = 0; i <= n; ++i) {
    scanf("%s", s);
    for (int j = 0; j < 1 << i; ++j) {
      if (s[j] == '1') {
        f[i][j] = 1;
      }
    }
  }
  for (int i = 1; i <= n; ++i) {
    for (int j = 0; j < 1 << i; ++j) {
      int b = j >> (i - 1) & 1, r = 0;
      for (; r < i && (j >> i - r - 1 & 1) == b; ++r);
      g[i][j] = r == i ? -1 : r;
    }
  }
  for (int i = 0; i <= n; ++i) {
    for (int j = 1; i + j <= n; ++j) {
      for (int k = 0; k < 1 << i + j; ++k) {
        f[i][k >> j] += f[i + j][k];
        int t = g[j][k & (1 << j) - 1];
        if (~t) {
          f[i + j - t][(k >> j << j - t) | (k & (1 << j - t) - 1)] += f[i + j][k];
        }
      }
    }
    for (int j = (1 << i) - 1; ~j; --j) {
      if (f[i][j] >= m) {
        len = i, ans = j;
      }
    }
  }
  for (int i = len - 1; ~i; --i) {
    putchar((ans >> i & 1) + '0');
  }
  putchar(10);
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

你可能感兴趣的:(Atcoder Grand Contest 024 简要题解)