Codeforces Round #632 (Div. 2) 题解
Codeforces Round #632 (Div. 2)
A. Little Artem
题意:略。
分析:构造这样的图形:
BWW...W
BWW...W
...
BWW...W
BBB...B
#include <bits/stdc++.h>
using namespace std;
void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
int main() {
io(); int t;
cin >> t;
while (t--) {
int n, m;
cin >> n >> m;
for (int i = 1; i < n; ++i) {
cout << "B";
for (int j = 1; j < m; ++j) cout << "W";
cout << "\n";
}
for (int i = 1; i <= m; ++i) cout << "B";
cout << "\n";
}
}
B. Kind Anton
题意:数组 \(a_n\) 由 \(\{-1,0,1\}\) 中的元素构成,并且你可以将数组中的任意元素 \(a_j\) 替换为 \(a_j+a_i(j>i)\) ,该操作能进行任意次,询问数组 \(a_n\) 能否通过变换变成数组 \(b_n\)
分析:如果 \(a_j<b_j\) ,那么必须存在 \(a_i=1(i<j)\) ;如果 \(a_j>b_j\) ,那么必须存在 \(a_i=-1(i<j)\) 。再特判 \(j=1\) 。
#include <bits/stdc++.h>
using namespace std;
void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
int main() {
io(); int t;
cin >> t;
while (t--) {
int n; cin >> n;
vector<int> a(n), b(n);
vector<vector<int> > vis(n, vector<int>(2));
for (auto& i : a) cin >> i;
bool f1, f2; f1 = f2 = false;
int cnt = 0;
for (auto i : a) {
if (i < 0) f1 = true;
if (i > 0) f2 = true;
vis[cnt][0] = f1;
vis[cnt++][1] = f2;
}
for (auto& i : b) cin >> i;
bool f = true;
if (a[0] != b[0]) f = false;
for (int i = 1; i < n; ++i) {
if (b[i] > a[i] && !vis[i - 1][1]) {
f = false;
break;
}
if (b[i] < a[i] && !vis[i - 1][0]) {
f = false;
break;
}
}
cout << (f ? "YES\n" : "NO\n");
}
}
C. Eugene and an array
题意:统计数组 \(a_n\) 中有几个连续子序列满足:该序列中不存在和为 \(0\) 的连续子序列。
分析:反过来统计和为 \(0\) 的子序列,然后减去。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
map<ll, ll> MP;
int main() {
io(); int n;
cin >> n;
MP[0] = 0;
ll r = -1, cur = 0, ans = 0;
for (int i = 1; i <= n; ++i) {
ll x; cin >> x;
cur += x;
if (MP.count(cur)) r = max(r, MP[cur]);
ans += r + 1;
MP[cur] = i;
}
ans = (n + 1ll) * n / 2 - ans;
cout << ans;
}
D. Challenges in school №41
题意:给定一个长度为 \(n\) 且由字符 \(L,R\) 构成的字符串,每轮操作中,你都能选择任意对相邻的 \(RL\) ,将其变为 \(LR\) ,询问能否正好用 \(k\) 轮将字符串中的 \(L\) 全部移动至左端, \(R\) 全部移动至右端。
分析:每一轮操作我们都贪心地将所有能够交换的位置互换,统计最少需要几轮才能完成交换(记为 \(cnt\) ),并统计交换的总次数(记为 \(sum\) ),如果 \(k\in[cnt,sum]\) 那么就可以给出交换方案,因为我们能将某一轮中的操作拆开来,最多能够拆成 \(sum\) 轮。
#include <bits/stdc++.h>
#define SIZE 3010
#define ll long long
using namespace std;
void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
vector<int> vec[SIZE];
char s[SIZE];
int main() {
io(); int n, k;
cin >> n >> k >> (s + 1);
int cnt = 0, sum = 0;
while (1) {
bool flag = false;
cnt++;
for (int i = 1; i < n; ++i) {
if (s[i] == 'R' && s[i + 1] == 'L') {
flag = true;
vec[cnt].emplace_back(i);
}
}
for (auto it : vec[cnt]) swap(s[it], s[it + 1]);
sum += vec[cnt].size();
if (!flag) break;
}
cnt--;
if (k < cnt || k > sum) {
cout << "-1";
return 0;
}
for (int i = 1; i <= cnt; ++i) {
while (!vec[i].empty() && k > cnt - i + 1) {
cout << "1 " << vec[i].back() << '\n';
vec[i].pop_back();
k--;
}
if (!vec[i].empty()) {
cout << vec[i].size();
for (auto it : vec[i]) cout << ' ' << it;
cout << '\n';
k--;
}
}
}
E. Road to 1600
题意:构造一个 \(n\times n\) 的棋盘,每个格子上的数字是 \(1,2,\cdots,n^2\) 。现在你控制两种棋子,分别是国际象棋中的车和后,从 \(1\) 出发,每一轮你能将棋子移动到所有可达并且未访问过的格子中最小的那个,花费为 \(0\) ;如果没有可以移动的格子,那么该棋子就会直接移动到当前棋盘上最小并且未访问过的格子,花费为 \(1\) 。构造一个车的花费严格小于后的棋盘。
分析:\(n<3\) 无法构造,然后考虑 \(n=3\) 的构造:
这个构造恰好能使得车比后少花费 \(1\) ,然后对于 \(n>3\) 的情况,我们只需要现在外面绕几圈,最后引导回这个 \(3\times 3\) 的棋盘中,形如:
#include <bits/stdc++.h>
using namespace std;
void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
int main() {
io(); int n;
cin >> n;
if (n < 3) { cout << "-1"; return 0; }
vector<vector<int> > ans(n + 2, vector<int>(n + 2, -1));
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
ans[i][j] = 0;
int top = n * n, cnt = 1, st = 0;
ans[1][1] = top - 1, ans[1][2] = top - 2, ans[1][3] = top - 3;
ans[2][1] = top - 4, ans[2][2] = top - 8, ans[2][3] = top - 7;
ans[3][1] = top - 5, ans[3][2] = top, ans[3][3] = top - 6;
pair<int, int> pr = make_pair(1, n);
if (n > 3) ans[1][n] = 1;
while (cnt < top - 9) {
if (st == 0) {
if (!ans[pr.first + 1][pr.second]) ++pr.first;
else --pr.second, ++st;
ans[pr.first][pr.second] = ++cnt;
}
else if (st == 1) {
if (!ans[pr.first][pr.second - 1]) --pr.second;
else --pr.first, ++st;
ans[pr.first][pr.second] = ++cnt;
}
else if (st == 2) {
if (!ans[pr.first][pr.second + 1]) ++pr.second;
else --pr.first, ++st;
ans[pr.first][pr.second] = ++cnt;
}
else {
if (!ans[pr.first - 1][pr.second]) --pr.first;
else --pr.second, st = 0;
ans[pr.first][pr.second] = ++cnt;
}
if (cnt == top - 9) {
if (ans[pr.first][pr.second + 1] == top - 10)
swap(ans[pr.first][pr.second], ans[pr.first][pr.second + 1]);
else swap(ans[pr.first][pr.second], ans[pr.first + 1][pr.second]);
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
cout << ans[i][j] << ' ';
}
cout << '\n';
}
}
F. Kate and imperfection
题意:在集合 \(S=\{1,2,\cdots,n\}\) 中,对于每个正整数 \(n\geq k>1\) ,找出一个大小为 \(k\) 的子集,使得该子集中两两间最大公因数的最大值最小,求这个最小值。
分析:我们考虑如何构造两两间最大公因数的最大值最小的集合,首先肯定是把所有质数先丢进集合里,然后再把与已经在集合内的数的最大公因数 \(=2\) 的数丢进去,然后是 \(=3\) 的数……然后注意到,如果我们加入了一个合数,那么他的所有因子必定已经在集合内了,于是加入的这个数字能够产生的最大公因数就是他的最大因子,因此用埃筛维护这个贪心的过程,排序一遍输出即可。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
int main() {
io(); int n;
cin >> n;
vector<int> ans(n + 1, 1);
for (int i = 2; i <= n; ++i) {
for (int j = i + i; j <= n; j += i) {
ans[j] = i;
}
}
sort(ans.begin(), ans.end());
for (int i = 2; i <= n; ++i) cout << ans[i] << ' ';
}