Rated for Div. 2 Educational Codeforces Round 137 A-F

比赛链接
A题解知识点:数学 。
\(4\) 位密码 , 由两个不同的数码组成,一共有 \(C_4^2\) 种方案 。从 \(10-n\) 个数字选两个,有 \(C_{10-n}^2\) 种方案 。结果为 \(3(10-n)(9-n)\) 。
时间复杂度 \(O(n)\)
空间复杂度 \(O(1)\)
代码#include <bits/stdc++.h>#define ll long longusing namespace std;bool solve() {int n;cin >> n;for (int i = 1;i <= n;i++) {int x;cin >> x;}cout << 3 * (10 - n) * (9 - n) << '\n';return true;}int main() {std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int t = 1;cin >> t;while (t--) {if (!solve()) cout << -1 << '\n';}return 0;}B题解知识点:构造 。
显然最小价值是 \(2\)。把 \(1\) 和 \(2\) 分两端放即可 。
时间复杂度 \(O(n)\)
空间复杂度 \(O(1)\)
代码#include <bits/stdc++.h>#define ll long longusing namespace std;bool solve() {int n;cin >> n;for (int i = 2;i <= n;i++) cout << i << ' ';cout << 1 << '\n';return true;}int main() {std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int t = 1;cin >> t;while (t--) {if (!solve()) cout << -1 << '\n';}return 0;}C题解【Rated for Div. 2 Educational Codeforces Round 137A-F】知识点:贪心 。
发现,可以将一段连续的盖子向左移,等效于把最后一个盖子移到第一个左边 。因此,找到一个无盖且右边连续有盖的位置,从连续有盖的一段选一个最小的和无盖的位置交换,如果最小的比无盖的大那就不交换 。
时间复杂度 \(O(n)\)
空间复杂度 \(O(n)\)
代码#include <bits/stdc++.h>#define ll long longusing namespace std;int a[200007];bool solve() {int n;cin >> n;string s;cin >> s;s = "?" + s;for (int i = 1;i <= n;i++) cin >> a[i];for (int i = 1;i <= n - 1;i++) {if (s[i] == '0' && s[i + 1] == '1') {int mi = i;for (int j = i + 1;j <= n && s[j] == '1';j++) {if (a[j] < a[mi]) mi = j;}swap(s[i], s[mi]);}}int sum = 0;for (int i = 1;i <= n;i++) {if (s[i] == '1') sum += a[i];}cout << sum << '\n';return true;}int main() {std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int t = 1;cin >> t;while (t--) {if (!solve()) cout << -1 << '\n';}return 0;}D题解知识点:枚举 。
第一个串显然是从第一个 \(1\) 开始截取到最后,现在考虑从第一个串截取出第二个串填补第一个串的 \(0\)。
显然要从第一个 \(0\) 开始填 。注意到,只有 \(0\) 前面的 \(1\) 可以通过截取向右移动与 \(0\) 重合 。枚举前面每个 \(1\) 通过截取与第一个 \(0\) 重合即可,截取方法有很多,第一种 , 以各个 \(1\) 为起点 , 截取固定长度 , 保持 \(1\) 与 \(0\) 重合;第二种,从第一个 \(1\) 开始截取,截取不同长度,使各个 \(1\) 和 \(0\) 重合 。
发现复杂度是和从第一个 \(1\) 开始连续 \(1\) 的长度有关 , 但因为是随机数据,因此不可能太长,可以看作常数 。
时间复杂度 \(O(n)\)
空间复杂度 \(O(n)\)
代码#include <bits/stdc++.h>using namespace std;int main() {std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int n;cin >> n;string s;cin >> s;int pos = s.find('1');if (!~pos) {cout << 0 << '\n';return 0;}string s1 = s.substr(pos);pos = s1.find('0');string ans = s1;for (int i = 0;i < pos;i++) {string s2 = s1;for (int j = pos;j < s1.size();j++) {if (s1[j - pos + i] == '1') s2[j] = '1';}ans = max(ans, s2);}cout << ans << '\n';return 0;}/* #include <bits/stdc++.h>using namespace std;string elz(string s) {for (int i = 0;i < s.size() - 1;i++)if (s[i] == '1') return s.substr(i);return s.substr(s.size() - 1);}int main() {std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int n;string s;cin >> n >> s;bitset<1000005> a(s), b(s);string ans = a.to_string();for (int i = 1;i <= 10;i++)ans = max(ans, (a | (b >> i)).to_string());cout << elz(ans) << '\n';return 0;} */E题解知识点:线性dp 。
考虑设 \(dp[i]\) 为造成不少于 \(i\) 点伤害的最小时间 。
先考虑 \(p_1,p_2\) 单独射击的转移:
dp[i] = min(dp[max(0LL, i - (p1 - s))] + t1, dp[max(0LL, i - (p2 - s))] + t2);再考虑,\(p_2\) 在 \(p_1\) 的 \(j\) 轮时间中调整,配合 \(p_1\) 在第 \(j\) 轮同时射击 。此时\(p_1\) 伤害是 \((j-1)(p_1 - s)\) ,\(p_2\) 伤害是 \(\lfloor\frac{(j\cdot t_1 - t_2)}{t_2}\rfloor(p_2-s)\)  , 同时射击伤害 \(p_1+p_2-s\),共计 \((j-1)(p_1 - s) + \lfloor\frac{(j\cdot t_1 - t_2)}{t_2}\rfloor(p_2-s) + (p_1+p_2-s)\)。(同理 \(p_1\) 配合 \(p_2\) 同时射击) 。
ll dmg = (j - 1) * (p1 - s) + (t1 * j - t2) / t2 * (p2 - s) + (p1 + p2 - s);dp[i] = min(dp[i], dp[max(0LL, i - dmg)] + t1 * j);

推荐阅读