Codeforces Round #710 (Div. 3)
比赛链接:https://codeforces.com/contest/1506
A. Strange Table
题解
所在行 \(row = n\ \ \ if\ \ \ x\ \%\ n = 0\ \ \ else\ \ \ x\ \%\ n\)
所在列 \(col = \lceil \frac{x}{n} \rceil\)
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
long long n, m, x;
cin >> n >> m >> x;
int row = x % n == 0 ? n : x % n;
int col = (x + n - 1) / n;
cout << (row - 1LL) * m + col << "\n";
}
return 0;
}
B. Partial Replacement
题解
模拟。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n, k;
cin >> n >> k;
string s;
cin >> s;
vector<int> pos;
for (int i = 0; i < n; i++) {
if (s[i] == '*') {
pos.push_back(i);
}
}
int ans = 0;
int cur = pos.front();
while (cur <= pos.back()) {
++ans;
if (cur == pos.back()) {
break;
}
cur = *prev(upper_bound(pos.begin(), pos.end(), cur + k));
}
cout << ans << "\n";
}
return 0;
}
C. Double-ended Strings
题解
即找 \(a\) 和 \(b\) 的最长公共子串。
方法比较多,枚举起点和终点、起点和长度、前后删去的字符长度均可。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
string a, b;
cin >> a >> b;
int n = a.length(), m = b.length();
int max_len = 0;
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
string sub_a = a.substr(i, j - i + 1);
if (b.find(sub_a) != string::npos) {
max_len = max(max_len, j - i + 1);
}
}
}
cout << n + m - 2 * max_len << "\n";
}
return 0;
}
D. Epic Transformation
题解
统计每个值的个数,如果某个值的个数比其他值的个数加起来还要多那么显然这个值一定会有剩余,否则都可以两两抵消( \(n\) 为奇数时会不可抗地剩一个)。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
int mx = 0;
map<int, int> mp;
for (int i = 0; i < n; i++) {
int x;
cin >> x;
++mp[x];
mx = max(mx, mp[x]);
}
if (mx > n / 2) {
cout << mx - (n - mx) << "\n";
} else {
cout << n % 2 << "\n";
}
}
return 0;
}
E. Restoring the Permutation
题解
模拟。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> q(n);
for (int i = 0; i < n; i++) {
cin >> q[i];
}
auto cal = [&](bool minimal) {
set<int> st;
for (int i = 1; i <= n; i++) {
st.insert(i);
}
for (int i = 0; i < n; i++) {
st.erase(q[i]);
}
vector<int> ans(n);
for (int i = 0; i < n; i++) {
if (i == 0 or q[i] != q[i - 1]) {
ans[i] = q[i];
} else {
auto it = minimal ? st.begin() : prev(st.lower_bound(q[i - 1]));
ans[i] = *it;
st.erase(it);
}
}
for (int i = 0; i < n; i++) {
cout << ans[i] << " \n"[i == n - 1];
}
};
cal(true), cal(false);
}
return 0;
}
F. Triangular Paths
题解
总的路径由相邻点移动而得,所以关键在于如何计算两点间的花费。
考虑题目中给的两种操作:
- \(r + c\) 为偶数,\(r = r + 1\),同时 \(r + c\) 奇偶性改变
- \(r + c\) 为奇数,\(r = r + 1, c = c + 1\),同时 \(r + c\) 奇偶性不变
如果两个点的 \(\triangle_r = \triangle_c\) ,那么有两种情况:
- \(r_1 + c_1\) 为奇数,此时可以一直无花费地移动到 \((r_2, c_2)\)
- \(r_1 + c_1\) 为偶数,此时只能一直给 $r, c $ 同时加一,花费为 \(\triangle_r = \triangle_c\)
如果两个点的 \(\triangle_r \neq \triangle_c\) ,此时一定为 \(\triangle_r > \triangle_c\) ,只需考虑 \(\triangle_r\) 比 \(\triangle_c\) 多出的部分,因为 \(\triangle_r\) 一定大于零,意味着 \(r_1 + c_1\) 的奇偶性至少会有一次改变,所以二者相等的部分可以在和为奇数时无花费地一直往右下方走直至抵消掉。
\(\triangle_r\) 比 \(\triangle_c\) 多出的部分 \(delta\) 有两种情况:
- \(delta\) 为偶数,这意味着 \(r_1 + c_1\) 有一半时间是奇数,一半时间是偶数,而和为偶数时执行 \(r_1 + 1\) 是无花费的,所以花费为 \(\frac{delta}{2}\)
- \(delta\) 为奇数,判断第一步是否有花费即可,接下来的 \(delta - 1\) 步与偶数的情况相同
代码
#include <bits/stdc++.h>
using namespace std;
int cal(int r1, int c1, int r2, int c2) {
int delta_r = r2 - r1, delta_c = c2 - c1;
if (delta_r == delta_c) {
return (r1 + c1) % 2 == 1 ? 0 : delta_r;
} else {
int extra = delta_r - delta_c;
if (extra % 2 == 0) {
return extra / 2;
} else {
return ((r1 + c1) % 2 == 1) + extra / 2;
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> r(n);
for (int i = 0; i < n; i++) {
cin >> r[i];
}
vector<int> c(n);
for (int i =0 ; i < n; i++) {
cin >> c[i];
}
vector<pair<int, int>> v(n);
for (int i = 0; i < n; i++) {
v[i] = {r[i], c[i]};
}
sort(v.begin(), v.end());
int ans = 0;
int cur_x = 1, cur_y = 1;
for (auto [next_x, next_y] : v) {
ans += cal(cur_x, cur_y, next_x, next_y);
cur_x = next_x, cur_y = next_y;
}
cout << ans << "\n";
}
return 0;
}
G. Maximize the Remaining String
题解
每次取后面有所有未用过字符的最大字符即可。
代码
#include <bits/stdc++.h>
using namespace std;
int distinct(string s) {
sort(s.begin(), s.end());
return unique(s.begin(), s.end()) - s.begin();
}
string filter(const string& s, char ch) {
string res;
bool found_first = false;
for (char c : s) {
if (c != ch and found_first) {
res += c;
} else if (c == ch) {
found_first = true;
}
}
return res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
string s;
cin >> s;
string ans;
set<char> unused(s.begin(), s.end());
while (not unused.empty()) {
char maxC = -1;
for (char c : unused) {
if (distinct(filter(s, c)) == int(unused.size()) - 1) {
maxC = max(maxC, c);
}
}
ans += maxC;
s = filter(s, maxC);
unused.erase(maxC);
}
cout << ans << "\n";
}
return 0;
}