VP Educational Codeforces Round 26
A. Text Volume
题意:统计每个单词大写字母个数的最大值。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::string s;
getchar();
std::getline(std::cin, s);
s += " ";
int ans = 0;
for (int i = 0, sum = 0; i <= n; ++ i) {
if (s[i] == ' ') {
ans = std::max(ans, sum);
sum = 0;
} else {
sum += s[i] >= 'A' && s[i] <= 'Z';
}
}
std::cout << ans << "\n";
}
B. Flag of Berland
题意:有三种颜色,判断是不是每种颜色各占一个三分之一大小的矩阵。
模拟题。
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<std::string> s(n);
for (int i = 0; i < n; ++ i) {
std::cin >> s[i];
}
auto check = [&](int x1, int y1, int x2, int y2, char c) -> bool {
for (int i = x1; i < x2; ++ i) {
for (int j = y1; j < y2; ++ j) {
if (s[i][j] != c) {
return false;
}
}
}
return true;
};
if (n % 3 == 0) {
std::string p = "RGB";
std::vector<int> id{0, 1, 2};
do {
if (check(0, 0, n / 3, m, p[id[0]]) &&
check(n / 3, 0, n / 3 * 2, m, p[id[1]]) &&
check(n / 3 * 2, 0, n, m, p[id[2]])) {
std::cout << "YES\n";
return;
}
} while (std::next_permutation(id.begin(), id.end()));
}
if (m % 3 == 0) {
std::string p = "RGB";
std::vector<int> id{0, 1, 2};
do {
if (check(0, 0, n, m / 3, p[id[0]]) &&
check(0, m / 3, n, m / 3 * 2, p[id[1]]) &&
check(0, m / 3 * 2, n, m, p[id[2]])) {
std::cout << "YES\n";
return;
}
} while (std::next_permutation(id.begin(), id.end()));
}
std::cout << "NO\n";
}
C. Two Seals
题意:一个\(a \times b\)的矩阵,有\(n\)个\(x_i \times y_i\)的印章,放两个进去不重叠能占多少面积。每个小矩阵可以旋转\(90\)度。
也是模拟,我们先把一个和左上角贴齐,然后判断是不是另一个能不能放下就行。枚举两个印章各自旋不旋转,各自放一遍。
点击查看代码
void solve() {
int n, a, b;
std::cin >> n >> a >> b;
std::vector<std::pair<int, int>> c(n);
for (int i = 0; i < n; ++ i) {
std::cin >> c[i].first >> c[i].second;
}
auto check = [&](int h1, int w1, int h2, int w2) -> int {
if (a < h1 || a < h2 || b < w1 || b < w2) {
return 0;
}
if (a - h1 >= h2 || b - w1 >= w2) {
return h1 * w1 + h2 * w2;
}
return 0;
};
int ans = 0;
for (int i = 0; i < n; ++ i) {
auto & [h1, w1] = c[i];
for (int j = i + 1; j < n; ++ j) {
auto & [h2, w2] = c[j];
ans = std::max(ans, check(h1, w1, h2, w2));
ans = std::max(ans, check(w1, h1, h2, w2));
ans = std::max(ans, check(w1, h1, w2, h2));
ans = std::max(ans, check(h1, w1, w2, h2));
}
}
std::cout << ans << "\n";
}
D. Round Subset
题意:\(n\)个数选\(k\)个数,使得某尾连续的零最多。
只有质因子\(2\)和\(5\)才能贡献末尾零,那么可以记\(f[i][j][x][y]\)表示前\(i\)个选了\(j\)个有\(x\)个\(2\)和\(y\)个\(5\)的值。但这样空间和时间都无法接受,发现其值其实就是\(\min(x, y)\),所以我们可以记\(f[i][j][x]\)表示有\(x\)个\(5\)的情况有多少个\(2\)。然后滚动数组优化即可。
点击查看代码
void solve() {
int n, k;
std::cin >> n >> k;
std::vector<i64> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
auto get = [&](i64 x) -> std::pair<int, int> {
int cnt2 = 0, cnt5 = 0;
while (x % 2 == 0) {
++ cnt2;
x /= 2;
}
while (x % 5 == 0) {
++ cnt5;
x /= 5;
}
return {cnt2, cnt5};
};
const int N = n * 26, inf = 1e9;
std::vector f(k + 1, std::vector<int>(N, -inf));
f[0][0] = 0;
int sum5 = 0;
for (int i = 0; i < n; ++ i) {
auto g = f;
auto [cnt2, cnt5] = get(a[i]);
for (int j = 0; j < k; ++ j) {
for (int x = 0; x <= sum5; ++ x) {
g[j + 1][x + cnt5] = std::max(g[j + 1][x + cnt5], f[j][x] + cnt2);
}
}
sum5 += cnt5;
f = g;
}
int ans = 0;
for (int i = 0; i <= sum5; ++ i) {
ans = std::max(ans, std::min(i, f[k][i]));
}
std::cout << ans << "\n";
}
E. Vasya's Function
题意:记\(f(a, 0) = 0, f(a, b) = 1 + f(a, b - gcd(a, b))\)。求\(f(a, b)\)。
这里\(a\)一直不变,导致暴力计算不能接受,模拟发现,\(b\)和\(a\)的\(gcd\)在不断增大,于是我们也许可以找下一次\(gcd\)变大需要多少次操作。这里要发现\(f(a, b) = f(\frac{a}{gcd(a, b)}, \frac{b}{gcd(a, b)})\),因为每次\(gcd\)增大后,我们可以让\(a, b\)都除以\(gcd(a, b)\),那么\(gcd(a, b)\)就变成了\(1\)。相当于整体缩小了。
那么我们每次找\(b\)最少减多少能使得\(gcd(a, b) \neq 1\),枚举\(a\)的因子即可,但发现因子也是\(a\)的质因子的倍数,所以可以枚举\(a\)的质因子。判断\(b\)到哪个质因子的倍数操作数最小。
点击查看代码
void solve() {
i64 n, m;
std::cin >> n >> m;
std::vector<i64> a;
i64 ans = 0;
while (m > 1) {
i64 min = m;
i64 t = n;
for (i64 i = 2; i * i <= n; ++ i) {
while (t % i == 0) {
min = std::min(min, m % i);
t /= i;
}
}
if (t > 1) {
min = std::min(min, m % t);
}
ans += min;
m -= min;
i64 d = std::gcd(n, m);
n /= d, m /= d;
}
ans += m;
std::cout << ans << "\n";
}