Atcoder Grand Contest 021 简要题解

Digit Sum 2:

如果 N N 除了最高位全是 9 答案就是 N N 的数位和,否则让 N 最高位减 1 1 其他位全是 9

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

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  char s[20];
  scanf("%s", s);
  bool flg = true;
  for (int i = 1; i < strlen(s); ++i) {
    if (s[i] != '9') {
      flg = false;
      break;
    }
  }
  if (flg) {
    int sum = 0;
    for (int j = 0; j < strlen(s); ++j) {
      sum += s[j] - '0';
    }
    printf("%d\n", sum);
  } else {
    printf("%d\n", strlen(s) * 9 + s[0] - '0' - 10);
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Holes:

对于每个 i i 分别求,枚举 j ,做 (Pi,Pj) ( P i , P j ) 的垂直平分线,限制就是在直线某一侧。

注意到 R R 非常大,可以平移所有直线到原点。

#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 = 105;
const double pi = acos(-1);

int n, m, b[N << 1];
double a[N << 1];
pii p[N];

inline double Fix(double x) {
  if (x < 0) {
    x += 2 * pi;
  }
  if (x >= 2 * pi) {
    x -= 2 * pi;
  }
  return x;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n);
  for (int i = 1; i <= n; ++i) {
    Read(p[i].X), Read(p[i].Y);
  }
  for (int i = 1; i <= n; ++i) {
    m = 0;
    for (int j = 1; j <= n; ++j) {
      if (i == j) {
        continue;
      }
      double l = atan2(p[j].Y - p[i].Y, p[j].X - p[i].X) - pi / 2, r = l + pi;
      l = Fix(l), r = Fix(r);
      a[++m] = l, a[++m] = r;
    }
    sort(a + 1, a + m + 1), m = unique(a + 1, a + m + 1) - a - 1;
    for (int j = 1; j <= m; ++j) {
      b[j] = 0;
    }
    for (int j = 1; j <= n; ++j) {
      if (i == j) {
        continue;
      }
      double l = atan2(p[j].Y - p[i].Y, p[j].X - p[i].X) - pi / 2, r = l + pi;
      l = Fix(l), r = Fix(r);
      int u = lower_bound(a + 1, a + m + 1, l) - a, v = lower_bound(a + 1, a + m + 1, r) - a;
      for (int x = u; x != v; b[x] = 1, x = x % m + 1);
    }
    double len = 0;
    for (int j = 1; j <= m; ++j) {
      if (!b[j]) {
        if (j == m) {
          len += Fix(a[1] - a[m]);
        } else {
          len += Fix(a[j + 1] - a[j]);
        }
      }
    }
    printf("%lf\n", len / pi / 2);
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Tiling:

尽量用 2 A A 或者 2 B B 2×2 的去覆盖,注意特判 (N,M,A,B)=(3,3,2,2) ( N , M , A , B ) = ( 3 , 3 , 2 , 2 ) 的情况。

#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 = 1005;

int n, m, a, b;
char s[N][N];

inline void A(int x, int y) {
  if (a) {
    s[x][y] = '<', s[x][y + 1] = '>', --a;
  }
}

inline void B(int x, int y) {
  if (b) {
    s[x][y] = '^', s[x + 1][y] = 'v', --b;
  }
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n), Read(m), Read(a), Read(b);
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= m; ++j) {
      s[i][j] = '.';
    }
  }
  if ((n & 1) && (m & 1) && n >= 3 && m >= 3) {
    for (int i = 1; i < m; i += 2) {
      A(n, i);
    }
    for (int i = 2; i < n; i += 2) {
      B(i, m);
    }
    bool flg = false;
    if (a & 1) {
      A(1, m - 1), B(1, m - 2), flg = true;
    }
    for (int i = 1; i < n; i += 2) {
      for (int j = 1; j < m; j += 2) {
        if (i == 1 && j == m - 2 && flg) {
          continue;
        }
        if (a) {
          A(i, j), A(i + 1, j);
        } else if (b) {
          B(i, j), B(i, j + 1);
        }
      }
    }
  } else {
    if (n & 1) {
      for (int i = 1; i < m; i += 2) {
        A(n, i);
      }
    }
    if (m & 1) {
      for (int i = 1; i < n; i += 2) {
        B(i, m);
      }
    }
    for (int i = 1; i < n; i += 2) {
      for (int j = 1; j < m; j += 2) {
        if (a) {
          A(i, j), A(i + 1, j);
        } else if (b) {
          B(i, j), B(i, j + 1);
        }
      }
    }
  }
  if (a || b) {
    puts("NO");
  } else {
    puts("YES");
    for (int i = 1; i <= n; ++i) {
      for (int j = 1; j <= m; ++j) {
        putchar(s[i][j]);
      }
      putchar(10);
    }
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Reversed LCS:

不难发现如果没有修改答案就是最长回文子序列, f(l,r,k) f ( l , r , k ) 表示当前考虑区间 [l,r] [ l , r ] 允许改 k k 次的答案。

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

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

inline int Solve(int l, int r, int k) {
  if (l >= r) {
    return r - l + 1;
  }
  if (f[l][r][k]) {
    return f[l][r][k];
  }
  f[l][r][k] = max(Solve(l + 1, r, k), Solve(l, r - 1, k));
  if (s[l] == s[r]) {
    CheckMax(f[l][r][k], Solve(l + 1, r - 1, k) + 2);
  } else if (k) {
    CheckMax(f[l][r][k], Solve(l + 1, r - 1, k - 1) + 2);
  }
  return f[l][r][k];
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  scanf("%s", s + 1), n = strlen(s + 1), Read(m);
  for (int i = 1; i <= n; ++i) {
    for (int j = i; j <= n; ++j) {
      CheckMax(ans, Solve(i, j, m));
    }
  }
  printf("%d\n", ans);
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Ball Eat Chameleons:

变色龙是红色的当且仅当它吃的红球比蓝球多,或者一样多且最后一个吃的是蓝球。

枚举红球个数 R ,记蓝球个数为 B B ,把问题认为在二维平面上走,从 (0,0) (R,B) ( R , B ) ,不难发现途中不能出现 yxRN+1 y − x ≥ R − N + 1 的情况,用类似卡特兰数的方法容斥一下就可以 O(1) O ( 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 = 500005;
const int mod = 998244353;

int n, m, ans, fac[N], inv[N];

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

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

Trinity:

f(i,j) f ( i , j ) 表示 i i j 列的答案,且要求每行非空,则 ans=ni=0(ni)f(i,m) a n s = ∑ i = 0 n ( n i ) f ( i , m )

考虑如何转移DP,每次新增一列,假设出现了 k k 行满足它们在 j+1 列第一次出现,那么就是 f(i,j)f(i+k,j+1) f ( i , j ) → f ( i + k , j + 1 ) ,考虑如何计算系数。

  • k=0 k = 0 ,如果第 j+1 j + 1 列为空,则方案数为 1 1 , 否则是 1x1x2i 的解数,为 (i+12) ( i + 1 2 )

  • k>0 k > 0 ,那么放置完新增的 k k 行之后,可以在上面选择一个比放置的第一行更小的行作为列最小值,在下面选择一个比放置的最后一行更大的行作为列最大值,也可以不放。把最小值往上平移一个单位,最大值往下平移一个单位,然后认为它们也是新增的行,不难发现答案为 (i+k+2k+2)

转移是卷积的形式,用FFT加速即可。​

#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 = 16385;
const int M = 15;
const int G = 3;
const int mod = 998244353;

namespace Polynomial {
  int D, L, I[M], W[M], R[N];

  inline int Qow(int x, int y) {
    int r = 1;
    for (; y; y >>= 1, x = 1LL * x * x % mod) {
      if (y & 1) {
        r = 1LL * r * x % mod;
      }
    }
    return r;
  }

  inline int Inv(int x) {
    return Qow(x, mod - 2);
  }

  inline void Ini(int l) {
    for (D = 1, L = 0; D < l; D <<= 1, ++L);
    for (int i = 1; i < D; ++i) {
      R[i] = (R[i >> 1] >> 1) | ((i & 1) << L - 1);
    }
    W[0] = Qow(G, mod - 1 >> L), I[0] = Inv(W[0]);
    for (int i = 1; i < L; ++i) {
      W[i] = 1LL * W[i - 1] * W[i - 1] % mod;
      I[i] = 1LL * I[i - 1] * I[i - 1] % mod;
    }
  }

  inline void DFT(int *X, int *W) {
    for (int i = 0; i < D; ++i) {
      if (i < R[i]) {
        swap(X[i], X[R[i]]);
      }
    }
    for (int i = 1, l = L - 1; i < D; i <<= 1, --l) {
      for (int j = 0; j < D; j += i << 1) {
        for (int k = 0, w = 1, u, v; k < i; ++k, w = 1LL * w * W[l] % mod) {
          u = X[j + k], v = 1LL * w * X[j + k + i] % mod;
          X[j + k] = (u + v) % mod, X[j + k + i] = (u - v + mod) % mod;
        }
      }
    }
  }
}

using namespace Polynomial;

int n, m, ans, f[N], g[N], h[N], fac[N], inv[N];

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

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n), Read(m), f[0] = fac[0] = fac[1] = inv[0] = inv[1] = 1;
  for (int i = 2; i <= n + 2; ++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 + 2; ++i) {
    inv[i] = 1LL * inv[i - 1] * inv[i] % mod;
  }
  Ini(n + 1 << 1);
  int v = Inv(D);
  for (int i = 1; i <= n; ++i) {
    g[i] = inv[i + 2];
  }
  DFT(g, W);
  for (int j = 1; j <= m; ++j) {
    for (int i = 0; i < D; ++i) {
      h[i] = i <= n ? 1LL * f[i] * inv[i] % mod : 0;
    }
    DFT(h, W);
    for (int i = 0; i < D; ++i) {
      h[i] = 1LL * h[i] * g[i] % mod;
    }
    DFT(h, I);
    for (int i = 0; i <= n; ++i) {
      f[i] = (1LL * h[i] * v % mod * fac[i + 2] + 1LL * f[i] * (C(i + 1, 2) + 1)) % mod;
    }
  }
  for (int i = 0; i <= n; ++i) {
    ans = (1LL * f[i] * C(n, i) + ans) % mod;
  }
  printf("%d\n", ans);
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AtCoder Beginner Contest 134 是一场 AtCoder 的入门级比赛,以下是每道题的简要题解: A - Dodecagon 题目描述:已知一个正十二边形的边长,求它的面积。 解题思路:正十二边形的内角为 $150^\circ$,因此可以将正十二边形拆分为 12 个等腰三角形,通过三角形面积公式计算面积即可。 B - Golden Apple 题目描述:有 $N$ 个苹果和 $D$ 个盘子,每个盘子最多可以装下 $2D+1$ 个苹果,求最少需要多少个盘子才能装下所有的苹果。 解题思路:每个盘子最多可以装下 $2D+1$ 个苹果,因此可以将苹果平均分配到每个盘子中,可以得到最少需要 $\lceil \frac{N}{2D+1} \rceil$ 个盘子。 C - Exception Handling 题目描述:给定一个长度为 $N$ 的整数序列 $a$,求除了第 $i$ 个数以外的最大值。 解题思路:可以使用两个变量 $m_1$ 和 $m_2$ 分别记录最大值和次大值。遍历整个序列,当当前数不是第 $i$ 个数时,更新最大值和次大值。因此,最后的结果应该是 $m_1$ 或 $m_2$ 中较小的一个。 D - Preparing Boxes 题目描述:有 $N$ 个盒子和 $M$ 个物品,第 $i$ 个盒子可以放入 $a_i$ 个物品,每个物品只能放在一个盒子中。现在需要将所有的物品放入盒子中,每次操作可以将一个盒子内的物品全部取出并分配到其他盒子中,求最少需要多少次操作才能完成任务。 解题思路:首先可以计算出所有盒子中物品的总数 $S$,然后判断是否存在一个盒子的物品数量大于 $\lceil \frac{S}{2} \rceil$,如果存在,则无法完成任务。否则,可以用贪心的思想,每次从物品数量最多的盒子中取出一个物品,放入物品数量最少的盒子中。因为每次操作都会使得物品数量最多的盒子的物品数量减少,而物品数量最少的盒子的物品数量不变或增加,因此这种贪心策略可以保证最少需要的操作次数最小。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值