VP Educational Codeforces Round 4
A. The Text Splitting
题意:给你一个字符串,你要把它分成若干个长度为\(p\)或者长度为\(q\)的字符串。
考虑枚举分成几个长度为\(p\)的字符串,剩下长度是\(q\)的倍数则合法。
点击查看代码
void solve() {
int n, a, b;
std::cin >> n >> a >> b;
std::string s;
std::cin >> s;
for (int i = 0; i <= n / a; ++ i) {
if ((n - i * a) % b == 0) {
std::cout << i + (n - i * a) / b << "\n";
int j = 0;
for (; j < i * a; j += a) {
std::cout << s.substr(j, a) << "\n";
}
for (; j < n; j += b) {
std::cout << s.substr(j, b) << "\n";
}
return;
}
}
std::cout << -1 << "\n";
}
B. HDD is Outdated Technology
题意:给你一个排列,你要按顺序从\(1\)走到\(n\),每次代价是两个位置坐标的差的绝对值,求总代价。
记录每个数出现的位置,然后从小到大记录。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n + 1);
for (int i = 1; i <= n; ++ i) {
int x;
std::cin >> x;
a[x] = i;
}
i64 ans = 0;
for (int i = 2; i <= n; ++ i) {
ans += std::abs(a[i] - a[i - 1]);
}
std::cout << ans << "\n";
}
C. Replace To Make Regular Bracket Sequence
题意:有四种左括号和右括号,每种类型的括号匹配形成一个合法的序列,你可以把任意一个括号变成另一个同左右类型的括号,问最少改变几个括号使得序列合法。
每个右括号是和离自己最近的左括号匹配的,那么用栈存每个左括号,遇到一个右括号则判断是不是同一类型的左括号,不是则需要改变一次。
点击查看代码
void solve() {
std::string s;
std::cin >> s;
std::stack<char> stk;
std::map<char, char> mp;
mp['}'] = '{';
mp[']'] = '[';
mp[')'] = '(';
mp['>'] = '<';
int ans = 0;
for (auto & c : s) {
if (c == ')' || c == '}' || c == ']' || c == '>') {
if (stk.empty()) {
std::cout << "Impossible\n";
return;
}
if (stk.top() != mp[c]) {
++ ans;
}
stk.pop();
} else {
stk.push(c);
}
}
if (stk.size()) {
std::cout << "Impossible\n";
return;
}
std::cout << ans << "\n";
}
D. The Union of k-Segments
题意:给你\(n\)个区间,求有多少区间至少被\(k\)个区间覆盖。
用差分的思想,把一个区间变成两个贡献:\((l, 1), (r, -1)\),然后从大到小遍历,记录每次值大于等于\(k\)的段的最左端点,直到小于\(k\)时加入答案即可。
点击查看代码
void solve() {
int n, k;
std::cin >> n >> k;
std::vector<std::pair<int, int>> a;
for (int i = 0; i < n; ++ i) {
int l, r;
std::cin >> l >> r;
a.push_back({l, 1});
a.push_back({r + 1, -1});
}
std::sort(a.begin(), a.end());
int sum = 0;
int last = 2e9;
std::vector<std::pair<int, int>> ans;
for (auto & [x, v] : a) {
sum += v;
if (sum >= k) {
last = std::min(last, x);
} else {
if (last <= x) {
ans.push_back({last, x - 1});
}
last = 2e9;
}
}
std::cout << ans.size() << "\n";
for (auto & [l, r] : ans) {
std::cout << l << " " << r << "\n";
}
}
E. Square Root of Permutation
题意:一个排列进行\(q_i = q_{q_i}\)的变化后变成了\(p\),现在给你一个\(p\),求一个合法的\(q\)。
对于\(q_i\),让\(i\)向\(q_i\)连边,那么因为每个点正好是一个出度一个入度,所以会形成若干个环。然后模拟方向,这个环到了\(p\)里会被打乱,每个位置指向的数是原来它指向的数的指向的数。那么每个环会根据位置的奇偶分成两个环,但发现奇数环的最后一个点会把两个环连接起来,所以如果环的长度是奇数,那么只需要两个两个跳着走还原奇数位置和偶数位置上的数,就可以得到原来的环。如果是长度为偶数的环,它会变成两个长度一样的环,那么可以两两匹配,一个环当成奇数位置的环一个环当成偶数位置的环,就可以用还原原来的环,如果没有匹配的则无解。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n + 1);
for (int i = 1; i <= n; ++ i) {
std::cin >> a[i];
}
std::vector<int> b(n + 1), vis(n + 1);
std::vector<int> pre(n + 1);
for (int i = 1; i <= n; ++ i) {
if (!vis[i]) {
std::vector<int> c;
while (!vis[i]) {
vis[i] = 1;
c.push_back(i);
i = a[i];
}
int m = c.size();
if (m & 1) {
std::vector<int> d(m);
for (int j = 0, k = 0; j < m; k = (k + 2) % m, ++ j) {
d[k] = c[j];
}
for (int j = 0; j < m; ++ j) {
b[d[j]] = d[(j + 1) % m];
}
} else {
if (pre[m]) {
std::vector<int> d(m * 2);
for (int j = 0, x = i, y = pre[m]; j < m * 2; ++ j) {
if (j % 2 == 0) {
d[j] = x;
x = a[x];
} else {
d[j] = y;
y = a[y];
}
}
for (int j = 0; j < m * 2; ++ j) {
b[d[j]] = d[(j + 1) % (m * 2)];
}
pre[m] = 0;
} else {
pre[m] = i;
}
}
}
}
for (int i = 2; i <= n; i += 2) {
if (pre[i]) {
std::cout << -1 << "\n";
return;
}
}
for (int i = 1; i <= n; ++ i) {
std::cout << b[i] << " \n"[i == n];
}
}
F. Simba on the Circle
待补