牛客小白月赛110
A. 智乃办赛
首先算出这个人在哪个字母里,然后对500取余就可以得到编号。
点击查看代码
void solve() {
int n;
std::cin >> n;
char c = (n - 1) / 500 + 'A';
n %= 500;
if (n == 0) {
n = 500;
}
std::string s = std::to_string(n);
while (s.size() < 3) {
s = "0" + s;
}
std::cout << c << s << "\n";
}
B. 智乃的Wordle
题意:比较两个长度为\(8\)的字符串,每一位如果相同就是\(g\),如果第二个字符串位置上的字符在第一个字符串里出现过就是\(y\),否则是\(r\)。
按题意模拟。
点击查看代码
void solve() {
std::string a, b;
std::cin >> a >> b;
std::vector<int> st(26);
for (auto & c : a) {
st[c - 'a'] = 1;
}
std::string s;
for (int i = 0; i < 8; ++ i) {
if (a[i] == b[i]) {
s += 'g';
} else if (st[b[i] - 'a']) {
s += 'y';
} else {
s += 'r';
}
}
std::cout << s << "\n";
if (std::count(s.begin(), s.end(), 'g') != 8) {
std::cout << "defeat\n";
} else {
std::cout << "congratulations\n";
}
}
C. 智乃的数字
题意:3的倍数和5的倍数且是奇数的数是好的,求第\(k\)个好的数。
考虑二分,一个数\(x\)前面有多少个好数?就是看有多少3的倍数和多少5的倍数,但要减去同时使3和5的倍数的数,但这样还会算上偶数,那么就减去同时是2和3的倍数已经是2和5的倍数的数,即减去6的倍数和10的倍数。同样道理,多减去的要加回来,那么要加去同时是6和10倍数的数,即加上30的倍数。
点击查看代码
void solve() {
i64 k;
std::cin >> k;
i64 l = 1, r = 1e18;
while (l < r) {
i64 mid = l + r >> 1;
if (mid / 3 + mid / 5 - mid / 15 - mid / 6 - mid / 10 + mid / 30 >= k) {
r = mid;
} else {
l = mid + 1;
}
}
std::cout << l << "\n";
}
D. 智乃与长短期主义者博弈
题意:两个人玩一个数组,每次只能从两端拿,第一个人在左边的数大于等于右边的情况下拿左边的,否则拿右边的,第二个人可以自己决定拿左边的还是右边的。两个人都希望最后拿的数总和最大,求最终结果。
可以用\(f[l][r]\)表示剩下区间为\([l, r]\)时第二个人可以取多少,记忆化搜索即可。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
int sum = std::accumulate(a.begin(), a.end(), 0);
std::vector f(n, std::vector<int>(n, -1));
auto dfs = [&](auto self, int l, int r, int flag) -> int {
if (l > r) {
return 0;
}
if (f[l][r] != -1) {
return f[l][r];
}
int res = 0;
if (flag == 1) {
if (a[l] >= a[r]) {
res = std::max(res, self(self, l + 1, r, flag ^ 1));
} else {
res = std::max(res, self(self, l, r - 1, flag ^ 1));
}
} else {
res = std::max(self(self, l + 1, r, flag ^ 1) + a[l], self(self, l, r - 1, flag ^ 1) + a[r]);
}
return f[l][r] = res;
};
int x = dfs(dfs, 0, n - 1, 1);
std::cout << sum - x << " " << x << "\n";
}
E. 智乃的跳跃排序
题意:给你一个数组,每个元素互不相同。你可以交换每个下标差的绝对值等于\(k\)的元素或者值的差的绝对值等于\(k\)的元素。问能不能使数组升序。
先把模\(k\)相同的一起排序,然后把值的差的绝对值等于\(k\)的排序。检查是否是升序即可。
点击查看代码
void solve() {
int n, k;
std::cin >> n >> k;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
auto b = a;
std::sort(b.begin(), b.end());
for (int i = 0; i < std::min(k, n); ++ i) {
std::vector<int> c;
for (int j = i; j < n; j += k) {
c.push_back(a[j]);
}
std::sort(c.begin(), c.end());
for (int j = i, l = 0; j < n; j += k) {
a[j] = c[l ++ ];
}
}
std::map<int, int> pos;
for (int i = 0; i < n; ++ i) {
pos[a[i]] = i;
}
for (int i = 0; i < n; ++ i) {
int x = b[i];
std::vector<int> p;
while (pos.count(x) && pos[x] != -1) {
p.push_back(pos[x]);
pos[x] = -1;
x += k;
}
std::sort(p.begin(), p.end());
for (int j = 0; j < p.size(); ++ j) {
a[p[j]] = j * k + b[i];
}
}
if (a != b) {
std::cout << "No\n";
} else {
std::cout << "Yes\n";
}
}