Educational Codeforces Round 179 (Rated for Div. 2)
A. Energy Crystals
题意:三个数,每次操作使得一个数增加任意数。但要保证任意两个数都有一个数大于等于另一个数的一半。求三个数都变成\(x\)的最少操作数。
首先把一个数变成\(1\),那么发现,之后没操作两步就能使得最大值乘二加一。那么需要\(log_2x \times 2\)的操作数把最大值变成\(x\),然后两次操作把另外两个数变成\(x\),加上一开始的一步,就是\(log_2x \times 2+3\)。
点击查看代码
void solve() {
int x;
std::cin >> x;
std::cout << std::__lg(x) * 2 + 3 << "\n";
}
B. Fibonacci Cubes
题意:有\(n\)个立方体,其中第\(i\)个边长为\(f_i\),\(f\)是斐波拉契数列的值。\(m\)次询问,问一个\(w\times l\times h\)的盒子能不能放下所有立方体。每个立方体不能有地方悬空,要么放在地面上要么放在另一个立方体上。
首先如果\(w, l, h\)中有一个小于\(f_n\),则无解。
否则如果\(h \geq f_n + f_{n-1}\),我们知道\(f_n = f_{n-1} + f_{n-2}\),那么可以把第\(n-1,n-2\)个立方体都放在第\(n\)个立方体上面,空出的另一半可以放\(f_{n-3},f_{n-4}\)...,依次类推,可以放完所有立方体。
如果\(max(w - f_n, l - f_n) > f_{n-1}\),则同理可以放完所有立方体。
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<int> f(n + 1);
f[1] = 1, f[2] = 2;
for (int i = 3; i <= n; ++ i) {
f[i] = f[i - 1] + f[i - 2];
}
while (m -- ) {
int w, l, h;
std::cin >> w >> l >> h;
if (w < f[n] || l < f[n] || h < f[n]) {
std::cout << "0";
continue;
}
if (f[n] + f[n - 1] <= h || w - f[n] >= f[n - 1] || l - f[n] >= f[n - 1]) {
std::cout << "1";
} else {
std::cout << "0";
}
}
std::cout << "\n";
}
C. Equal Values
题意:给你一个数组\(a\),每次选择一个\(i\),花费\((i-1)\times a_i\)把左边都变成\(a_i\),或者花费\((n-i)\times a_i\)把右边都变成\(a_i\)。求数组所有数相同的最小花费。
要么操作第一个数把右边都变成它,要么操作最后一个数把左边都变成它,要么选两个相同的数操作。
选两个数也有两种操作,假设选了\(i, j\),那么可以操作\(i\)的右边和\(j\)的左边,显然应该选最近的两个相同的数。如果\([i, j]\)之间的数都相同,那么可以操作\(i\)的左边和\(j\)右边。
所有情况取最小值就行。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<i64> a(n + 1);
for (int i = 1; i <= n; ++ i) {
std::cin >> a[i];
}
if (std::ranges::count(a, a[1]) == n) {
std::cout << 0 << "\n";
return;
}
i64 ans = std::min(a[1], a[n]) * (i64)(n - 1);
std::vector<int> last(n + 1);
for (int i = 1; i <= n; ++ i) {
if (last[a[i]]) {
ans = std::min(ans, ((i64)n - last[i] + i - 1) * a[i]);
}
ans = std::min(ans, ((i64)n - i + i - 1) * a[i]);
last[a[i]] = i;
}
for (int i = 1; i <= n; ++ i) {
int j = i;
while (j + 1 <= n && a[j + 1] == a[i]) {
++ j;
}
ans = std::min(ans, ((i64)i - 1 + n - j) * a[i]);
i = j;
}
std::cout << ans << "\n";
}
D. Creating a Schedule
题意:用给定的\(m\)个数填一个\(n\times 6\)的矩阵,使得每列没有相同的数。其价值定义为每行相邻两个数去除末尾两位后的差的绝对值。求价值最大的矩阵。
如果给你恰好\(n\)个数,那么应该按列先从小到大填,然后从大到小填,这样循环。这样的价值是最大的,可以把每对相邻点想象为一条线段,线段的长度就是这两个数产生的价值,那么我们应该尽可能让长的的线段多,于是这样排列就能保证最大。考虑有多于\(n\)个数的情况,我们应该选前\(n / 2\)个最小的和后\(n / 2\)个最大的,如果\(n\)是奇数,它可以选剩下的数里最大的最小的循环交替出现。
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<i64> a(m);
for (int i = 0; i < m; ++ i) {
std::cin >> a[i];
}
std::ranges::sort(a);
std::vector<i64> b;
int l = 0, r = m - 1;
for (; l < r; ++ l, -- r) {
if (b.size() + 2 <= n) {
b.push_back(a[l]);
b.push_back(a[r]);
} else {
break;
}
}
std::ranges::sort(b);
std::vector ans(n, std::array<i64, 6>{});
for (int j = 0; j < 6; ++ j) {
if (j & 1) {
for (int i = 0, k = 0; i < n; ++ i) {
if (n % 2 && i == n / 2) {
ans[i][j] = a[l];
} else {
ans[i][j] = b[k ++ ];
}
}
} else {
for (int i = n - 1, k = 0; i >= 0; -- i) {
if (n % 2 && i == n / 2) {
ans[i][j] = a[r];
} else {
ans[i][j] = b[k ++ ];
}
}
}
}
for (int i = 0; i < n; ++ i) {
for (int j = 0; j < 6; ++ j) {
std::cout << ans[i][j] << " \n"[j == 5];
}
}
}
E. Changing the String
题意:给你一个只包含\(a, b, c\)的字符串,有\(m\)次操作,每次让你把一类字符的一个变成另一个字符。你也可以无视任意这个操作。求最小字典序。
要想字典序最小,我们可以从前往后考虑,让前面的尽可能小。
如果\(s[i] = a\),不进行操作。
如果\(s[i] = b\),那么优先\(b\)->\(a\)其次是\(b\)->\(c\)->\(a\)。
如果\(s[i] = c\),那么优先\(c\)->\(a\),其次是\(c\)->\(b\)->\(a\),再就是\(c\)->\(b\)。
那么我们可以\(set\)记录每个操作的位置,\(S[i][j]\)记录了\(i\)->\(j\)的所有操作的下标。那么只需要从前往后模拟,按优先级处理,每次用最前的操作,注意\(b\)->\(c\)->\(a\)这种需要\(c\)->\(a\)的操作位置在\(b\)->\(c\)操作的后面,可以用set的lower_bound查找。
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::string s;
std::cin >> s;
std::set<int> S[3][3]{};
for (int i = 0; i < m; ++ i) {
char a, b;
std::cin >> a >> b;
S[a - 'a'][b - 'a'].insert(i);
}
for (int i = 0; i < n; ++ i) {
if (s[i] == 'a') {
continue;
}
if (s[i] == 'b') {
if (S[1][0].empty()) {
if (S[1][2].empty()) {
continue;
}
auto it = S[2][0].lower_bound(*S[1][2].begin());
if (it != S[2][0].end()) {
s[i] = 'a';
S[1][2].erase(S[1][2].begin());
S[2][0].erase(it);
}
} else {
s[i] = 'a';
S[1][0].erase(S[1][0].begin());
}
} else {
if (S[2][0].empty()) {
if (S[2][1].size()) {
s[i] = 'b';
auto it = S[1][0].lower_bound(*S[2][1].begin());
if (it != S[1][0].end()) {
s[i] = 'a';
S[1][0].erase(it);
}
S[2][1].erase(S[2][1].begin());
}
} else {
s[i] = 'a';
S[2][0].erase(S[2][0].begin());
}
}
}
std::cout << s << "\n";
}