「题解」Codeforces Round 905 (Div. 3)

before

终于有一篇题解是一次性更所有题的了。

A. Morning

Problem

A. Morning

Sol&Code

根据题意模拟即可。

#include <bits/stdc++.h>

typedef long long ll;

int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }

int T;

int main() {
  scanf("%d", &T);
  while (T--) {
    std::string s;
    std::cin >> s;
    int now = 1, ans = 1;
    for (int i = 0; i < 4; ++i) {
      if (now == s[i] - '0') ++ans;
      else {
        ans += std::abs(((s[i] - '0') ? (s[i] - '0') : 10) - (now ? now : 10)) + 1;
        now = s[i] - '0';
      }
    }
    printf("%d\n", ans - 1);
  }
  return 0;
}

B. Chemistry

Problem

B. Chemistry

Sol&Code

回文与否只与字符出现次数有关。

从长为 \(n\) 的字符串中删去 \(k\) 个字符,若最后的串长度 \((n - k)\) 为奇数,首先需要原串中出现奇数次的字符的数量不超过 \(k + 1\),若最后的串长度 \((n - k)\) 为奇数,需要原串中出现奇数次的字符的数量不超过 \(k\)。保证出现奇数次的字符数量合适后只需要剩下的删除字符次数为偶数即可。分类讨论可得,只要满足了前者,后者就得到了保证。(真神奇)

#include <bits/stdc++.h>

typedef long long ll;

int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }

int T, n, k, odd, cnt[648];
std::string s;

int main() {
  scanf("%d", &T);
  while (T--) {
    scanf("%d %d", &n, &k);
    std::cin >> s;
    for (int i = 'a'; i <= 'z'; ++i) cnt[i] = 0;
    for (int i = 0; i < n; ++i) ++cnt[s[i]];
    bool okay = true;
    if ((n - k) & 1) {
      odd = 0;
      for (int i = 'a'; i <= 'z'; ++i) {
        if (cnt[i] & 1) ++odd;
      }
      if (odd - 1 > k) okay = false;
    } else {
      odd = 0;
      for (int i = 'a'; i <= 'z'; ++i) {
        if (cnt[i] & 1) ++odd;
      }
      if (odd > k) okay = false;
    }
    puts(okay ? "YES" : "NO");
  }
  return 0;
}

C.Raspberries

Problem

C.Raspberries

Sol&Code

\(k\) 只有四种情况。

对每种情况分类讨论凑出因子的情况即可。

#include <bits/stdc++.h>
#define N 100001

typedef long long ll;

int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }

int T, n, k, a[N];

int main() {
  scanf("%d", &T);
  while (T--) {
    scanf("%d %d", &n, &k);
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    if (k == 2) {
      int ans = 1;
      for (int i = 1; i <= n; ++i) {
        if (!(a[i] & 1)) ans = 0;
      }
      printf("%d\n", ans);
    }
    if (k == 3) {
      int ans = 2;
      for (int i = 1; i <= n; ++i) {
        if (a[i] % 3 == 0) { ans = 0; break; }
        if (a[i] % 3 == 2) { ans = 1; }
      }
      printf("%d\n", ans);
    }
    if (k == 4) {
      int cnt = 0, ans = 3;
      for (int i = 1; i <= n; ++i) {
        if (a[i] % 4 == 0) { ans = 0; break; }
        if (a[i] % 4 == 3) { ans = min(ans, 1); }
        if (a[i] % 4 == 2) { ans = min(ans, 2); }
        if (a[i] % 4 == 1) { ans = min(ans, 3); }
        if (a[i] % 2 == 0) ++cnt;
      }
      if (cnt >= 2) printf("%d\n", 0);
      if (cnt == 1) printf("%d\n", min(1, ans));
      if (cnt == 0) printf("%d\n", min(2, ans));
    }
    if (k == 5) {
      int ans = 4;
      for (int i = 1; i <= n; ++i) {
        if (a[i] % 5 == 0) { ans = 0; break; }
        if (a[i] % 5 == 2) { ans = min(ans, 3); }
        if (a[i] % 5 == 3) { ans = min(ans, 2); }
        if (a[i] % 5 == 4) { ans = min(ans, 1); }
      }
      printf("%d\n", ans);
    }
  }
  return 0;
}

D. In Love

Problem

D. In Love

Sol&Code

不相交即满足最小的右端点的位置小于最大的左端点的位置

multiset可以满足插入、删除、有序的需求

#include <bits/stdc++.h>
#define N 100001
#define fir first
#define sec second

typedef long long ll;
typedef std::pair<int, int> pii;

int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }

int T;
class Pair {
  public:
    Pair(int x, int y) : a(x), b(y) {}
    int a, b;
};

bool cmp1(const Pair& p1, const Pair& p2) {
  if (p1.a == p2.a) return p1.b < p2.b;
  return p1.a < p2.a;
}

bool cmp2(const Pair& p1, const Pair& p2) {
  if (p1.b == p2.b) return p1.a < p2.a;
  return p1.b < p2.b;
}

std::multiset<Pair, decltype(cmp1)*> s1(cmp1);
std::multiset<Pair, decltype(cmp2)*> s2(cmp2);

int main() {
  scanf("%d", &T);
  while (T--) {
    getchar();
    char ch;
    int a, b;
    ch = getchar();
    scanf("%d %d", &a, &b);
    if (ch == '+') {
      s1.insert(Pair(a, b));
      s2.insert(Pair(a, b));
    } else {
      s1.erase(s1.find(Pair(a, b)));
      s2.erase(s2.find(Pair(a, b)));
    }
    bool okay = true;
    if (s1.size() < 2) okay = false;
    else if ((*s2.begin()).b >= (*(--s1.end())).a) okay = false;
    puts(okay ? "YES" : "NO");
  }
  return 0;
}

E. Look Back

Problem

E. Look Back

Sol&Code

\(log\) 后避免了爆炸的问题 \(·2\) 变为 \(+1\)

#include <bits/stdc++.h>
#define N 100001
#define eps 1e-10

typedef long long ll;

int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }

double b[N];
int T, n, a[N];

int main() {
  scanf("%d", &T);
  while (T--) {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    for (int i = 1; i <= n; ++i) b[i] = std::log(a[i]) / std::log(2.0);
    long long ans = 0;
    for (int i = 2; i <= n; ++i) {
      if (b[i - 1] - b[i] >= eps) {
        double cha = b[i - 1] - b[i];
        int ad = cha;
        if (cha - ad >= eps) ans += ad + 1, b[i] += ad + 1;
        else ans += ad, b[i] += ad;
      }
    }
    printf("%lld\n", ans);
  }
  return 0;
}

F. You Are So Beautiful

Problem

F. You Are So Beautiful

Sol&Code

对于原文中的一串 \(s_l s_{l + 1} s_{l + 2} \dots s_r\) 只出现一次即保证 \(l\) 前没有出现过 \(s_l\)\(r\) 后没有出现过 \(s_r\)。若其中任意一个出现过则与 \(s_l s_{l + 1} s_{l + 2} \dots s_r\) 相同的子序列不唯一,没有出现过则左端点与右端点固定了。题目转化为了维护第一次出现的字符的个数。

#include <bits/stdc++.h>
#define N 100001
#define lowbit(x) (x & -x)

typedef long long ll;

int T, n, a[N], bit[N];

void add(int x) {
  while (x <= n) {
    ++bit[x];
    x += lowbit(x);
  }
}

ll ask(int x, ll res = 0) {
  while (x > 0) {
    res += bit[x];
    x -= lowbit(x);
  }
  return res;
}

int main() {
  scanf("%d", &T);
  while (T--) {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) bit[i] = 0;
    std::map<int, int> mp;
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    for (int i = n; i >= 1; --i) {
      ++mp[a[i]];
      if (mp[a[i]] == 1) add(n - i + 1);
    }
    std::map<int, int> mp2;
    ll ans = 0;
    for (int i = 1; i <= n; ++i) {
      ++mp2[a[i]];
      if (mp2[a[i]] == 1) ans += ask(n - i + 1);
    }
    printf("%lld\n", ans);
  }
  return 0;
}

G1. Dances (Easy version)

Problem

Dances (Easy version)

Sol&Code

贪心的用双指针从小到大匹配 \(a\) 中元素与 \(b\) 中比该元素稍大的元素。

#include <bits/stdc++.h>
#define N 100001

int T, n, m, a[N], b[N];

int main() {
  scanf("%d", &T);
  while (T--) {
    scanf("%d %d", &n, &m);
    a[1] = m;
    for (int i = 2; i <= n; ++i) scanf("%d", &a[i]);
    for (int i = 1; i <= n; ++i) scanf("%d", &b[i]);
    std::sort(a + 1, a + n + 1);
    std::sort(b + 1, b + n + 1);
    int l = 1, r = 1, ans = 0;
    while (l <= n && r <= n) {
      while (l <= n && r <= n && b[r] > a[l]) ++l, ++r, ++ans;
      ++r;
    }
    printf("%d\n", n - ans);
  }
  return 0;
}

G2. Dances (Hard Version)

Problem

G2. Dances (Hard Version)

Sol&Code

一个数在不断变大的过程中最多使答案变大 \(1\) 一次。即该数由匹配到不匹配。

二分找什么时候变大即可。

#include <bits/stdc++.h>
#define N 100001

int T, n, m, k, a[N], b[N], c[N];

bool check(int x, int res = 0) {
  c[1] = x;
  for (int i = 2; i <= n; ++i) c[i] = a[i];
  std::sort(c + 1, c + n + 1);
  int p1 = 1, p2 = 1;
  while (p1 <= n && p2 <= n) {
    while (p1 <= n && p2 <= n && c[p1] < b[p2]) ++p1, ++p2, ++res;
    ++p2;
  }
  return res < k;
}

int main() {
  scanf("%d", &T);
  while (T--) {
    scanf("%d %d", &n, &m); a[1] = 1;
    for (int i = 2; i <= n; ++i) scanf("%d", &a[i]);
    for (int i = 1; i <= n; ++i) scanf("%d", &b[i]);
    std::sort(a + 1, a + n + 1);
    std::sort(b + 1, b + n + 1);
    int p1 = 1, p2 = 1; k = 0;
    while (p1 <= n && p2 <= n) {
      while (p1 <= n && p2 <= n && a[p1] < b[p2]) ++p1, ++p2, ++k;
      ++p2;
    }
    int l = 1, r = m;
    while (l <= r) {
      int mid = (l + r) >> 1;
      if (check(mid)) r = mid - 1;
      else l = mid + 1;
    }
    printf("%lld\n", 1ll * (n - k) * (l - 1) + 1ll * (n - k + 1) * (m - l + 1));
  }
  return 0;
}

After

赛时 \(E\) 精度出了问题。精度鲨我,害怕,救救。

还是做的太慢。

\(G2\) 好像有不用二分的做法。

posted @ 2023-10-26 12:05  yu__xuan  阅读(105)  评论(1编辑  收藏  举报