「題解」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\) 好像有不用二分的做法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章