Codeforces Round #612 (Div. 2)
比赛链接:https://codeforces.com/contest/1287
A - Angry Students
题意
有一字符串由 'A','P' 组成,每分钟 'A' 可以使右边相邻的 'P' 变为 'A',问字符串稳定下来需要多少分钟。
题解
查找每个 'A' 后的最长连续 'P' 串。
代码
#include <bits/stdc++.h> using namespace std; void solve() { int k; string s; cin >> k >> s; int ans = 0; for (int i = 0; i < k; i++) { if (s[i] == 'A') { ++i; int cnt = 0; while (i < k and s[i] == 'P') ++cnt, ++i; ans = max(ans, cnt); --i; } } cout << ans << "\n"; } int main() { int t; cin >> t; while (t--) solve(); }
B - Hyperset
题意
有 n 个长为 k ,由 'S', 'E', 'T' 组成的字符串,若三个字符串同一位置的字符全部相同或两两不同,我们称之为一个三元组,试找出 n 个字符串中三元组的个数(不考虑三个字符串的前后顺序)。(1≤n≤1500,1≤k≤30)
题解
若枚举三个字符串的情况则复杂度高达 $O_{(n^3k)}$,显然是不现实的,注意到,当前两个字符串确定后第三个字符串也已经确定了,所以可以记录每个字符串的个数,枚举前两个字符串的情况然后查询第三个字符串的个数,当然这样同一个三元组会计入三次,所以最后的结果需要再除以三。这样就可以在 $O_{(n^2k)}$ 的时间复杂度内解决该问题。
代码
#include <bits/stdc++.h> using LL = long long; using namespace std; int main() { int n, k; cin >> n >> k; map<string, LL> mp; string s[n]; for (auto &i : s) cin >> i, mp[i]++; LL ans = 0; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { string des(k, '0'); for (int _ = 0; _ < k; _++) { if (s[i][_] == s[j][_]) des[_] = s[i][_]; else for (char c : {'S', 'E', 'T'}) { if (c != s[i][_] and c != s[j][_]) des[_] = c; } ans += mp[des]; } } cout << ans / 3 << "\n"; }
C - Garland
题意
有一个残缺的排列,空位置为 0,求补全后奇偶相邻的最少对数。
题解
dp[i][j][0] 表示当前第 i 个位置为偶数,位置 [1, i] 中共有 j 个偶数。
dp[i][j][1] 表示当前第 i 个位置为奇数,位置 [1, i] 中共有 j 个偶数。
代码
#include <bits/stdc++.h> using namespace std; const int M = 110; int a[M], dp[M][M][2]; int main() { int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; memset(dp, M, sizeof dp); dp[0][0][0] = dp[0][0][1] = 0; for (int i = 1; i <= n; i++) { for (int j = 0; j <= i; j++) { if (a[i] == 0) { dp[i][j][0] = min(dp[i - 1][j - 1][0], dp[i - 1][j - 1][1] + 1); dp[i][j][1] = min(dp[i - 1][j][1], dp[i - 1][j][0] + 1); } else { if (a[i] % 2 == 0) dp[i][j][0] = min(dp[i - 1][j - 1][0], dp[i - 1][j - 1][1] + 1); if (a[i] % 2 == 1) dp[i][j][1] = min(dp[i - 1][j][1], dp[i - 1][j][0] + 1); } } } cout << min(dp[n][n / 2][0], dp[n][n / 2][1]); }
D - Numbers on Tree
题意
给一棵树的结点赋值,要求每棵子树中值小于根节点 i 的结点个数为 ci 。
题解
从最深的子节点开始构造,依次把每个结点插入当前第 ci 大的位置。
代码
#include <bits/stdc++.h> using namespace std; const int M = 2200; int c[M], ans[M]; vector<int> e[M], v; int dfs(int u) { int sz = 1; for (int v : e[u]) sz += dfs(v); if (u != 0) { if (c[u] >= sz) { cout << "NO" << "\n"; exit(0); } v.insert(v.begin() + c[u], u); } return sz; } int main() { int n; cin >> n; for (int i = 1; i <= n; i++) { int u; cin >> u >> c[i]; e[u].push_back(i); } dfs(0); for (int i = 0; i < v.size(); i++) ans[v[i]] = i + 1; cout << "YES" << "\n"; for (int i = 1; i <= n; i++) cout << ans[i] << ' '; }

浙公网安备 33010602011771号