Codeforces Round #638 (Div. 2)
比赛链接:https://codeforces.com/contest/1348
A - Phoenix and Balance
题意
将长为偶数的等比数列 $2^1, 2^2, 2^3, ... , 2^n$ 分为两个长为 $\frac{n}{2}$,相差最小的子序列。
题解
原序列可以看做一个二进制数,比如当 $n = 6$ 时:
原序列可以看做:$111111$
相差最小的分法即为:
$100011$
$011100$
代码
#include <bits/stdc++.h> using namespace std; void solve() { int n; cin >> n; int a = 0, b = 0; a += 1 << n; for (int i = 1; i < n / 2; i++) { a += 1 << i; } for (int i = n / 2; i < n; i++) { b += 1 << i; } cout << a - b << "\n"; } int main() { int t; cin >> t; while (t--) solve(); }
B - Phoenix and Beauty
题意
向一个长为 $n$ 的数组中插入一些数,使得每个长为 $k$ 的连续子数组的和为定值。
题解
利用原数组中的值构造构造一个大小为 $k$ 的循环数组,将原数组中的每个数都用该循环数组代替。
代码
#include <bits/stdc++.h> using namespace std; void solve() { int n, k; cin >> n >> k; set<int> st; for (int i = 0; i < n; i++) { int x; cin >> x; st.insert(x); } if (st.size() > k) { cout << "-1" << "\n"; return; } if (st.size() < k) { for (int i = 1; i <= n; i++) { st.insert(i); if (st.size() == k) break; } } cout << n * k << "\n"; for (int i = 0; i < n; i++) { for (int j : st) cout << j << ' '; } cout << "\n"; } int main() { int t; cin >> t; while (t--) solve(); }
C - Phoenix and Distribution
题意
将字符串 $s$ 分为 $k$ 个非空串,找出使得 $k$ 个非空串中字典序最大的字符串字典序最小的方案。
题解
先给每个字符串分配一个字母保证非空,此时如果只剩下一种字母,给字典序最小的一些字符串循环分配即可。
如果剩下的字母多于一种,则全部分给一个字符串,因为这样分较大的字母最靠后,字典序最小。
代码
#include <bits/stdc++.h> using namespace std; void solve() { int n, k; cin >> n >> k; string str; cin >> str; int cnt[26] = {}; for (char c : str) cnt[c - 'a']++; string s[k]; vector<char> init_s; int len = -1; for (int i = 0; i < 26; i++) { if (cnt[i] > 0) { if (len == -1) len = min(k, cnt[i]); int need = k - init_s.size(); int mi = min(need, cnt[i]); for (int j = 0; j < mi; j++) { init_s.push_back(char('a' + i)); } cnt[i] -= mi; } } for (int i = 0; i < k; i++) { s[i] += init_s[i]; } int type = 0; for (int i = 0; i < 26; i++) { type += cnt[i] > 0; } for (int i = 0; i < 26; i++) { if (cnt[i] > 0) { for (int j = 0; j < cnt[i]; j++) { if (type == 1) s[j % len] += char('a' + i); else s[0] += char('a' + i); } } } sort(s, s + k); cout << s[k - 1] << "\n"; } int main() { int t; cin >> t; while (t--) solve(); }
D - Phoenix and Science
题意
开始时有 $1$ 个质量为 $1$ 的细菌,白天可以选择部分细菌分裂,晚上每个细菌的质量增加 $1$,问最少需要多少天总质量能达到 $m$,输出分裂方案。
题解
- 细菌分裂只影响之后每晚增加的质量
考虑质量增长最快的方式——指数增长:每个白天所有的细菌都分裂,这样每晚增加的质量即为一个 $a_0 = 1,\ q = 2$ 的等比数列,求出和小于等于 $m$ 的最长等比数列,将多出来的质量分进其中的某一天即可,相邻两晚的质量之差即为白天多分裂的个数。
代码
#include <bits/stdc++.h> using namespace std; void solve() { int n; cin >> n; vector<int> m; for (int i = 1; i <= n; i *= 2) { m.push_back(i); n -= i; } if (n > 0) { m.push_back(n); sort(m.begin(), m.end()); } cout << m.size() - 1 << "\n"; for (int i = 1; i < m.size(); i++) cout << m[i] - m[i - 1] << " \n"[i == m.size() - 1]; } int main() { int t; cin >> t; while (t--) solve(); }