Codeforces 选做#1

教练要求做的题,难度可能有些简单。

Codeforces 22D. Segments

考虑每个线段按照右节点排序后,贪心选取即可。

时间复杂度 (mathcal O(nlog n))

#include <bits/stdc++.h>

using namespace std;

const int N = 1005;

int n;

struct line {
  int l, r;
} seg[N];

bool vis[N];

int main() {
  scanf("%d", &n);
  for (int i = 1; i <= n; i++) {
    scanf("%d %d", &seg[i].l, &seg[i].r);
    if (seg[i].l > seg[i].r) swap(seg[i].l, seg[i].r);
  }
  sort(seg + 1, seg + 1 + n, [](line lhs, line rhs) {
    if (lhs.r == rhs.r) return lhs.l < rhs.l;
    return lhs.r < rhs.r;
  });
  vector<int> ans;
  for (int i = 1; i <= n; i++) {
    if (!vis[i]) {
      ans.emplace_back(seg[i].r);
      int j = i + 1;
      while (seg[j].l <= seg[i].r) {
        vis[j] = 1;
        j++;
      }
    }
  }
  printf("%d
", ans.size());
  for (auto i : ans) printf("%d ", i);
  return 0;
}

Codeforces 9D. How many trees?

(f[i][j]) 表示前 (i) 个数,深度为 (j) 的方案数。

考虑枚举左右节点的深度,即

[f[i+1][j]=sum_k f[i][L] imes f[i-k][R] ]

/*
 * Author: chhokmah
 * Date: 2020-08-22 09:48:35
 */
#include <bits/stdc++.h>

using namespace std;

const int N = 40;

int n, k;
long long f[N][N];

int main() {
  scanf("%d %d", &n, &k);
  f[1][1] = f[0][0] = 1;
  for (int i = 1; i < n; i++) {
    for (int j = 0; j <= i; j++) {
      for (int left = 0; left <= i; left++) {
        for (int right = 0; right <= i - j; right++) {
          f[i + 1][max(left, right) + 1] += f[j][left] * f[i - j][right];
        }
      }
    }
  }
  long long ans = 0;
  for (int i = k; i <= n; i++) ans += f[n][i];
  printf("%I64d
", ans);
  return 0;
}

Codeforces 7D. Palindrome Degree

考虑一个 (mathcal O(nlog n)) 的暴力。

考虑优化这个暴力,我们记录前缀的答案,然后可以把 (O(log n)) 的缩小优化为 (O(1))

时间复杂度 (mathcal O(n))

/*
 * Author: chhokmah
 * Date: 2020-08-22 10:40:34
 */
#include <bits/stdc++.h>

using namespace std;

constexpr int N = 5e6 + 5;

template <int base, int mod>
struct hash_st {
  constexpr static int Base = base, P = mod;

  int64_t hashp[N], hashs[N], ord[N];
  string s;
  int n;

  void prep() {
    ord[0] = 1;
    for (int i = 1; i <= n; i++) ord[i] = ord[i - 1] * Base % P;
    hashp[0] = s[0];
    for (int i = 1; i < n; i++) hashp[i] = (hashp[i - 1] * Base + s[i]) % P;
    hashs[n - 1] = s[n - 1];
    for (int i = n - 2; i >= 0; i--)
      hashs[i] = (hashs[i + 1] * Base + s[i]) % P;
  }

  hash_st() {}
  hash_st(string st) { s = st, n = s.length(), prep(); }

  void init(string st) { s = st, n = s.length(), prep(); }

  int64_t getp(int l, int r) {
    return l == 0 ? hashp[r]
                  : (hashp[r] - hashp[l - 1] * ord[r - l + 1] % P + P) % P;
  }

  int64_t gets(int l, int r) {
    return r == n - 1 ? hashs[l]
                      : (hashs[l] - hashs[r + 1] * ord[r - l + 1] % P + P) % P;
  }
};

string s;
hash_st<129, 998244353> hash1;
int dp[N];

bool chk(int l, int r) { return hash1.getp(l, r) == hash1.gets(l, r); }

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  cin >> s;
  bool flag = 0;
  int n = s.length(), ans = 0;
  for (int i = 1; i < n; i++)
    if (s[0] != s[i]) flag = 1;
  if (!flag) {
    for (int i = 1; i <= n; i++) ans += log2(i) + 1;
    cout << ans << '
';
    return 0;
  }
  hash1.init(s);
  for (int i = 0; i < n; i++) {
    int cnt = 0, len = i + 1;
    if (chk(0, i)) {
      dp[i]++;
      len >>= 1;
      if (chk(i - len + 1, i) && len >= 1) dp[i] += dp[len - 1];
      ans += dp[i];
    }
  }
  cout << ans << '
';
  return 0;
}

Codeforces 8E. Beads

比较好的一道题,我们先考虑概括其约束:

  • 原串 $leq $ 逆串 (iff) 前缀 $leq $ 后缀
  • 原串 $leq $ 反串 (iff)(1) 位为 (0)
  • 原串 $leq $ 逆反串 (iff) 前缀 $leq $ 后缀的逆串

我们考虑一位一位确定答案,我们需要计算当前这一位为 (0) 的方案数,并不断和 (k) 靠近。

时间复杂度 (mathcal O(50n^2))

需要注意奇数的情况的细节处理。

/*
 * Author: chhokmah
 * Date: 2020-08-22 14:07:51
 */
#include <bits/stdc++.h>

using namespace std;

int n;
long long k;
long long dp[55][2][2];
int a[55];

long long numberDigitDp(int r, int flag1, int flag2) {
  if (r < n - r + 1) return 1;
  if (dp[r][flag1][flag2] != -1) return dp[r][flag1][flag2];
  long long& ans = dp[r][flag1][flag2];
  ans = 0;
  if (r == n - r + 1) {
    for (int i = 0; i <= 1; i++)
      if (a[r] == i || a[r] == -1)
        if ((!flag2 || (flag2 && i <= (i ^ 1))))
          ans += numberDigitDp(r - 1, flag1 & 1, flag2 & 0);
  } else {
    for (int i = 0; i <= 1; i++)
      if (a[n - r + 1] == i || a[n - r + 1] == -1)
        for (int j = 0; j <= 1; j++)
          if (a[r] == j || a[r] == -1)
            if ((!flag1 || (flag1 && i <= j)) &&
                (!flag2 || (flag2 && i <= (j ^ 1))))
              ans += numberDigitDp(r - 1, flag1 & (i == j), flag2 & (i != j));
  }
  return ans;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);
  cout.tie(nullptr);
  cin >> n >> k;
  memset(a, -1, sizeof a);
  memset(dp, -1, sizeof dp);
  a[1] = 0;
  if (numberDigitDp(n, 1, 1) <= k) {
    printf("-1
");
    return 0;
  }
  printf("0");
  for (int i = 2; i <= n; i++) {
    memset(dp, -1, sizeof dp);
    a[i] = 0;
    long long pro = numberDigitDp(n, 1, 1);
    if (pro <= k) {
      printf("1");
      k -= pro;
      a[i] = 1;
    } else
      printf("0");
  }
  return 0;
}
原文地址:https://www.cnblogs.com/chhokmah/p/13545979.html