比赛链接:Here

1367A. Short Substrings

一个字符串 abac,然后把所有长度为2的子串加起来变成新串,abbaac,由 ab ba ac组成。现在给出新串,找出原串。

直接模拟即可

  1. int main() {
  2. cin.tie(nullptr)->sync_with_stdio(false);
  3. int _; for (cin >> _; _--;) {
  4. string s; cin >> s;
  5. cout << s[0];
  6. for (int i = 1; i < s.size(); i += 2) cout << s[i];
  7. cout << "\n";
  8. }
  9. }

1367B. Even Array

给定一个数组。有一种操作,可以交换任意两个数的位置。要求的数组奇偶交替出现。最少需要多少次操作。

先统计一遍都多少个奇数不在位置上,和多少个偶数不在位置上。如果不相等,那么无解。反之,把他们放到对应的位置就好了。

  1. int main() {
  2. cin.tie(nullptr)->sync_with_stdio(false);
  3. int _; for (cin >> _; _--;) {
  4. int n; cin >> n;
  5. vector<int> a(n);
  6. for (int &x : a) cin >> x;
  7. int cnt0 = 0, cnt1 = 0, ans = 0;
  8. for (int i = 0; i < n; ++i) {
  9. cnt0 += a[i] % 2;
  10. cnt1 += i % 2;
  11. if (i % 2 == 1 && a[i] % 2 == 0) ans += 1;
  12. }
  13. if (cnt0 != cnt1) cout << "-1\n";
  14. else cout << ans << "\n";
  15. }
  16. }

1367C. Social Distance

给定一个01串。需要保证两个相邻的1之间的距离大于k。求原串在不违背题意的情况下,还能插入多少个1。

这个需要分情况考虑。左边连续的0单独计数。右边连续的0单独计数。中间出现的连续的0单独计数。

  1. int main() {
  2. cin.tie(nullptr)->sync_with_stdio(false);
  3. int _; for (cin >> _; _--;) {
  4. int n, k; string s;
  5. cin >> n >> k >> s;
  6. int sum = 0, cnt = 0, pre = 0;
  7. k += 1;
  8. bool f = false;
  9. for (int i = 0; i < n; ++i) {
  10. if (s[i] == '0') cnt += 1;
  11. else {
  12. f = true;
  13. if (pre == 0) sum += max(0, cnt / k);
  14. else sum += max(0, (cnt - k + 1) / k);
  15. pre = 1, cnt = 0;
  16. }
  17. }
  18. sum += max(0, cnt / k);
  19. if (!f) sum = max(1 + max(0, (n - 1) / k), sum);
  20. cout << sum << "\n";
  21. }
  22. }
  1. int main() {
  2. cin.tie(nullptr)->sync_with_stdio(false);
  3. int _; for (cin >> _; _--;) {
  4. int n, k; string s;
  5. cin >> n >> k >> s;
  6. int sum = 0, cnt1 = 0, cnt0 = 0;
  7. for (int i = 0; i < n; ++i) {
  8. if (s[i] == '1') {
  9. cnt1 += 1;
  10. if (cnt1 == 1)
  11. sum += cnt0 / (k + 1);
  12. else {
  13. sum += (cnt0 - k) / (k + 1);
  14. cnt1 = 1;
  15. }
  16. cnt0 = 0;
  17. }
  18. if (s[i] == '0') cnt0 += 1;
  19. if (i == n - 1 && s[i] == '0' && cnt1 != 0)
  20. sum += cnt0 / (k + 1);
  21. }
  22. if (cnt1 == 0) sum += (cnt0 + k) / (k + 1);
  23. cout << sum << "\n";
  24. }
  25. }

1367D. Task On The Board

给定s串,删除一些字符,重新组合,得到t串。根据t串,可以计算一个b数组。$b_i = sum(|j-i|)$ if $t_j > t_i$,也就是所有比i位置大的字符的位置差的和。现在给定s和b数组,求t串。

首先肯定是找 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图1 数组为 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图2 的位置。因为Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图3 ,就表示,没有比他更大的字符了。然后这些位置填上了字符之后,对于非 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图4 的位置,他们都是有贡献的。把这些贡献从 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图5 数组中减掉,就又会尝试新的 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图6 的位置。就循环模拟这个过程就好了。

  1. const int N = 50;
  2. int b[N];
  3. int main() {
  4. cin.tie(nullptr)->sync_with_stdio(false);
  5. int _; for (cin >> _; _--;) {
  6. string s; int m;
  7. cin >> s >> m;
  8. for (int i = 0; i < m; ++i) cin >> b[i];
  9. int cnt[30] = {};
  10. for (auto c : s) cnt[c - 'a'] += 1;
  11. int r = m, l = 25;
  12. string t(m, '?');
  13. while (r) {
  14. int c = 0;
  15. for (int i = 0; i < m; ++i)
  16. if (!b[i]) c += 1;
  17. while (cnt[l] < c) l -= 1;
  18. for (int i = 0; i < m; ++i) {
  19. if (!b[i]) {
  20. t[i] = 'a' + l;
  21. b[i] -= 1;
  22. r -= 1;
  23. }
  24. }
  25. for (int i = 0; i < m; ++i) {
  26. if (t[i] == 'a' + l)
  27. for (int j = 0; j < m; ++j)
  28. if (b[j] > 0) b[j] -= abs(i - j);
  29. }
  30. l -= 1;
  31. }
  32. cout << t << "\n";
  33. }
  34. }

1367E. Necklace Assembly

给定一堆字符。然后选出len个,围成一圈。且以k为循环节。即每转动k次,这个圈看上去是一模一样的。给定k。求最大的len。

Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图7 为循环节。那么以 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图8 的因子 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图9 为循环节都可以。所以先枚举 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图10 的所有因子。然后对于每个循环节 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图11 ,如果只由 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图12 个元素组成。那显然是可以的。但是要要枚举 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图13 ,可不可以,Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图14 可不可以,直到找到一个最大的 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图15 可行。那么对于循环节 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图16 。最大长度就是 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图17 。对所有枚举到的取 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图18 就好了。

  1. int check(int k, int cnt[]) {
  2. int tmp = k;
  3. for (int j = 2;; j += 1) {
  4. int tt = 0;
  5. for (int i = 0; i < 26; ++i) tt += cnt[i] / j;
  6. if (tt >= k) tmp = j * k;
  7. else return tmp;
  8. }
  9. }
  10. int main() {
  11. cin.tie(nullptr)->sync_with_stdio(false);
  12. int _; for (cin >> _; _--;) {
  13. int cnt[100] = {};
  14. string s;
  15. int n, m;
  16. cin >> n >> m >> s;
  17. for (int i = 0; i < n; ++i) cnt[s[i] - 'a'] += 1;
  18. sort(cnt, cnt + 100);
  19. reverse(cnt, cnt + 100);
  20. int ans = 1;
  21. for (int i = 1; i <= m && i <= n; ++i) {
  22. if (m % i == 0)
  23. ans = max(ans, check(i, cnt));
  24. }
  25. cout << ans << "\n";
  26. }
  27. }

1367F1. Flying Sort (Easy Version)

一个数组,一次操作可以选择一个数,放到数组开头,或者放到末尾。问最少多少次操作可以使得数组有序。Easy版中所有元素各不相同。且数组长度 $< 3000$。

超级经典 DP + 离散化处理,⭐一下

考虑求不需要动的元素。先对 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图19 数组离散化,变成值域 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图20 的数组。然后不需要动的元素是差值为 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图21 的连续上升子序列。DP 求这个最大长度就好了。其他的数都是要移动的。并且要移动一个数。至多只移动一次就好了。所以求出最长子序列长度,再用 Codeforces Round #650 (Div. 3) 很好的一场,F1经典离散化DP - 图22 减去就是答案了。

  1. const int N = 1e6 + 10;
  2. int a[N], b[N], f[N];
  3. int main() {
  4. cin.tie(nullptr)->sync_with_stdio(false);
  5. int _; for (cin >> _; _--;) {
  6. int n; cin >> n;
  7. for (int i = 0; i < n; ++i) cin >> b[i], a[i] = b[i];
  8. sort(b, b + n);
  9. for (int i = 0; i <= n ; ++i) f[i] = 0;
  10. for (int i = 0; i < n; ++i) a[i] = lower_bound(b, b + n, a[i]) - b + 1;
  11. int ans = 0;
  12. for (int i = 0; i < n; ++i) {
  13. f[a[i]] = f[a[i] - 1] + 1;
  14. ans = max(ans, f[a[i]]);
  15. }
  16. cout << n - ans << "\n";
  17. }
  18. }

1367F2. Flying Sort (Hard Version)

AC参考代码

  1. const int N = 2e5 + 10;
  2. int a[N], p[N];
  3. int main() {
  4. cin.tie(nullptr)->sync_with_stdio(false);
  5. int _; for (cin >> _; _--;) {
  6. int n; cin >> n;
  7. for (int i = 0; i < n; ++i) cin >> a[i];
  8. iota(p, p + n, 0);
  9. sort(p, p + n, [&](int i, int j) {return a[i] < a[j] || a[i] == a[j] && i < j;});
  10. int ans = 0;
  11. for (int l = 0, r; l < n; l = r) {
  12. for (r = l + 1; r < n && p[r] > p[r - 1]; ++r);
  13. int cnt = r - l;
  14. if (l)
  15. for (int i = l - 1; i >= 0 && a[p[i]] == a[p[l - 1]]; i--)
  16. if (p[i] < p[l]) cnt += 1;
  17. if (r < n)
  18. for (int i = r; i < n && a[p[i]] == a[p[r]]; ++i)
  19. if (p[i] > p[r - 1]) ++ cnt;
  20. ans = max(ans, cnt);
  21. }
  22. for (int l = 0, m, r; l < n; l = m) {
  23. for (m = l; m < n && a[p[m]] == a[p[l]]; ++m);
  24. if (m == n) break;
  25. for (r = m; r < n && a[p[r]] == a[p[m]]; ++r);
  26. for (int i = l, j = m; i < m; ++i) {
  27. while (j < r && p[j] < p[i]) ++j;
  28. ans = max(ans, i + 1 - l + r - j);
  29. }
  30. }
  31. cout << n - ans << "\n";
  32. }
  33. }