C o d e f o r c e s R o u n d 923 ( D i v . 3 ) ( A − E ) \Huge{Codeforces Round 923 (Div. 3)(A-E)} CodeforcesRound923(Div.3)(A−E)
比赛地址:Codeforces Round 923 (Div. 3)
Problems A. Make it White
思路
题目给出一个用’W’和’B’组成的字符串,分别代表白色和黑色。选中一个区域并将其刷为白色,要求刷完后字符串全为白色,问选中区域最短为多少。
找出第一个’B’和最后一个’B’即可。
标程
void Solved() {
int n; cin >> n;
string s; cin >> s;
int l = -1, r;
for(int i = 0; i < n; i ++ ) {
if(s[i] == 'B') {
l = i; break;
}
}
for(int i = n - 1; i >= 0; i -- ) {
if(s[i] == 'B') {
r = i; break;
}
}
if(l == -1) cout << "0" << endl;
else cout << r - l + 1 << endl;
}
Problems B. Following the String
思路
本题为构造题,根据题目给定的一个数组来构造出一个由小写字母构成的字符串。
数组表示的是当前位置前面有多少与这个位置相同的字符。
这道题直接用map来存前面每个字母出现的次数,然后模拟即可。
标程
void Solved() {
int n; cin >> n;
vector<int> a(n);
map<char, int> mp;
for(auto &i : a) cin >> i;
int t = 0;
for(int i = 0; i < n; i ++ ) {
if(a[i] == 0) {
char ch = 'a' + t;
cout << ch;
t ++;
mp[ch] ++;
continue;
}
for(int j = 0; j < 26; j ++ ) {
char ch = 'a' + j;
if(mp[ch] == a[i]) {
cout << ch;
mp[ch] ++; break;
}
}
}
cout << endl;
}
Problems C. Choose the Different Ones!
思路
题目给出 n , m , k n,m,k n,m,k,然后给出一个长度为 n n n的数组和一个长度为 m m m的数组。要求从每个数组中选出 k 2 \frac{k}{2} 2k个数字,要求选出来的数组可以构成 1 − k 1-k 1−k。
枚举 1 − k 1-k 1−k:
- 如果该数字只在 a a a中出现,则 x + + x++ x++。
- 如果只在 b b b中出现,则 y + + y++ y++。
- 如果两个中都没有出现,则输出
NO
。 - 如果在两个数组中都出现,
continue
。
最后判断
x
x
x和
y
y
y有没有大于
k
2
\frac{k}{2}
2k,大于输出NO
,否则YES
。
标程
void Solved() {
int n, m, k; cin >> n >> m >> k;
map<int, int> mp1, mp2;
bool flag = false;
int t, x = 0, y = 0;
for(int i = 0; i < n; i ++ ) {
cin >> t; mp1[t] = 1;
}
for(int i = 0; i < m; i ++ ) {
cin >> t; mp2[t] = 1;
if(mp1[t]) continue;
}
for(int i = 1; i <= k; i ++ ) {
if(mp1[i] == 1 && mp2[i] == 1) continue;
if(mp1[i] == 0 && mp2[i] == 0) {
flag = true; break;
}
if(mp1[i] == 1) x ++;
else y ++;
}
if(x > k / 2 || y > k / 2) flag = true;
if(flag) cout << "NO" << endl;
else cout << "YES" << endl;
}
Problems D. Find the Different Ones!
思路
给你一个由 n n n个整数组成的数组 a a a和 q q q个查询。要求每次查询的区间 [ l , r ] [l,r] [l,r]中有没有不相等的元素,并输出任意一组不相同的元素。
根据数据范围,暴力必T。
我们考虑先用前缀和来维护区间中是否有不相同的数字,具体做法为:
- 题目要求输出数字的下标。
- 我们可以再声明一个数组 b b b,然后从后向前遍历,如果与上一个数字相同,则存入上一个数字的下标,否则存入当前位置的下标。
- 然后在查询的过程中,每次询问 [ l , r ] [l,r] [l,r],若 b l < r b_l<r bl<r,则代表在该区间内存在不相等的数字,那么结果即为: l + 1 , b l + 1 l + 1, b_l+1 l+1,bl+1。
- b l + 1 b_l+1 bl+1是区间内与 a l a_l al不相等的数字下标(因为前面判断过 b l < r b_l<r bl<r,所以 b l + 1 b_l+1 bl+1是在区间内。
标程
void Solved() {
int n; cin >> n;
vector<int> a(n), b(n);
for(auto &i : a) cin >> i;
b[n - 1] = n;
for(int i = n - 2; i >= 0; i -- ) {
if(a[i] == a[i + 1]) b[i] = b[i + 1];
else b[i] = i + 1;
}
int m; cin >> m;
while(m -- ) {
int l, r; cin >> l >> r;
l --;
if(b[l] < r) cout << l + 1 << " " << b[l] + 1 << endl;
else cout << "-1 -1\n";
}
cout << endl;
}
Problems E. Klever Permutation
思路
本题为构造体题,给出 n , k n,k n,k,要求构造出来一个由 1 − n 1-n 1−n组成的长度为 n n n的数组,并且所有连续长度为 k k k的子数组相差不超过 1 1 1 。
我们先考虑相邻两个长度为 k k k的子数组,我们会发现前一个子数组的第一个和后一个子数组的最后一个元素只能相差为 1 1 1,因为其中间都为重叠的元素。
那么我们会发现,对于有相交的子数组,其不相交部分差值不能超过 1 1 1。按这样进行构造,当其不相交时,其偏差也不会大于1。
并且,保证所有子数组的偏差小于 1 1 1,较小数应与较大数能够在同一个子数组中,例如:
当 n = 10 , k = 4 n=10,k=4 n=10,k=4时:
1 10 4 7 2 9 5 6 3 8
根据这一规则很容易就可以推导出符合要求的数组的构造方式。
标程
void Solved() {
int n, k; cin >> n >> k;
vector<int> a(n);
int l = 1, r = n;
for(int i = 0; i < k; i ++ ) {
if(i % 2 == 0) {
for(int j = i; j < n; j += k)
a[j] = r --;
} else {
for(int j = i; j < n; j += k)
a[j] = l ++;
}
}
for(int i = 0; i < n; i ++ )
cout << a[i] << " \n"[i == n - 1];
}