Codeforces Round 784 (Div. 4) 题解
A. Division?
题目大意:
Codeforces根据用户等级将其划分为 444 类:
-第1部分: 1900≤rating1900 \leq \mathrm{rating}1900≤rating
-部分2: 1600≤rating≤18991600 \leq \mathrm{rating} \leq 18991600≤rating≤1899
-对于分区3: 1400≤rating≤15991400 \leq \mathrm{rating} \leq 15991400≤rating≤1599
-分区4: rating≤1399\mathrm{rating} \leq 1399rating≤1399
给定一个 rating\mathrm{rating}rating ,打印 rating\mathrm{rating}rating 属于哪个组别。
样例输入
7
-789
1299
1300
1399
1400
1679
2300
样例输出
Division 4
Division 4
Division 4
Division 4
Division 3
Division 2
Division 1
思路
多个if判断即可
代码
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n;
cin >> n;
if(n >= 1900) cout << "Division 1" << endl;
else if(n >= 1600) cout << "Division 2" << endl;
else if(n >= 1400) cout << "Division 3" << endl;
else cout << "Division 4" << endl;
}
signed main() {
int t = 1;
cin >> t;
for(int i = 1; i <= t; i++)
solve();
return 0;
}
B. Triple
题目大意:
给定一个包含 nnn 元素的数组 aaa ,打印任何出现至少三次的值,如果没有出现则打印-1。
样例输入
7
1
1
3
2 2 2
7
2 2 3 3 4 2 2
8
1 4 3 4 3 2 4 1
9
1 1 1 2 2 2 3 3 3
5
1 5 2 4 3
4
4 4 4 4
样例输出
-1
2
2
4
3
-1
4
思路
map统计出现次数,输出超过三次的即可
代码
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n; cin >> n;
map<int, int> mp;
for(int i = 0; i < n; i++) {
int k; cin >> k;
mp[k]++;
}
int res = 0;
for(auto &[a, b] : mp)
if(b >= 3) {
res++;
cout << a << " ";
break;
}
if(res == 0) cout << -1;
cout << endl;
}
signed main() {
int t = 1;
cin >> t;
for(int i = 1; i <= t; i++)
solve();
return 0;
}
C. Odd/Even Increments
题目大意:
给定一个包含 nnn 个正整数的数组 a=[a1,a2,…,an]a=[a_1,a_2,\dots,a_n]a=[a1,a2,…,an] ,你可以对它进行两种类型的操作:
-
将 111 添加到每一个奇数索引的元素。也就是说,将数组修改为: a1:=a1+1,a3:=a3+1,a5:=a5+1,…a_1 := a_1 +1, a_3 := a_3 + 1, a_5 := a_5+1, \dotsa1:=a1+1,a3:=a3+1,a5:=a5+1,… 。
-
将 111 添加到每个具有偶数索引的元素。换句话说,将数组修改为: a2:=a2+1,a4:=a4+1,a6:=a6+1,…a_2 := a_2 +1, a_4 := a_4 + 1, a_6 := a_6+1, \dotsa2:=a2+1,a4:=a4+1,a6:=a6+1,… 。
确定在任意数量的操作之后,是否有可能使最终数组只包含偶数或只包含奇数。
换句话说,确定是否可以在任意次数的操作之后使数组的所有元素具有相同的奇偶校验。
注意,这两种类型的操作可以执行任意次数(甚至不执行)。不同类型的操作可以执行不同的次数。
样例输入
4
3
1 2 1
4
2 2 2 3
4
2 2 2 2
5
1000 1 1000 1 1000
样例输出
YES
NO
YES
YES
思路
偶数位与奇数位的操作都是互相独立的,单独判断。
不难发现,只有当偶数位的所有数字奇偶性一样并且奇数位的所有数字奇偶性一样最后的结果才能一样。
分别统计奇偶位上奇数的数量即可。
代码
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n; cin >> n;
int a[2] = {0};
for(int i = 1; i <= n; i++) {
int k; cin >> k;
a[i % 2] += k % 2;
}
if(a[0] != 0 and a[0] != n / 2) {
cout << "NO\n";
return ;
}
if(a[1] != 0 and a[1] != n / 2 + n % 2) {
cout << "NO\n";
return ;
}
cout << "YES\n";
}
signed main() {
int t = 1;
cin >> t;
for(int i = 1; i <= t; i++)
solve();
return 0;
}
D. Colorful Stamp
题目大意:
给出了一行 nnn 单元格,最初都是白色的。使用图章,您可以在任意两个相邻的单元格上图章,使一个单元格变成红色,另一个单元格变成蓝色。邮票可以旋转,即它可以以两种方式使用:作为 BR\color{blue}{\texttt{B}}\color{red}{\texttt{R}}BR 和作为 RB\color{red}{\texttt{R}}\color{blue}{\texttt{B}}RB 。
在使用期间,戳记必须完全适合给定的 nnn 单元格(它不能部分地在单元格之外)。戳可以多次应用于同一单元格。每次使用图章都会对图章下的两个单元格重新上色。
例如,制作图片 BRBBW\color{blue}{\texttt{B}}\color{red}{\texttt{R}}\color{blue}{\texttt{B}}\color{blue}{\texttt{B}}\texttt{W}BRBBW 的一个可能的邮票序列可以是 WWWWW→WWRB‾W→BR‾RBW→BRB‾BW\texttt{WWWWW} \to \texttt{WW}\color{brown}{\underline{\color{red}{\texttt{R}}\color{blue}{\texttt{B}}}}\texttt{W} \to \color{brown}{\underline{\color{blue}{\texttt{B}}\color{red}{\texttt{R}}}}\color{red}{\texttt{R}}\color{blue}{\texttt{B}}\texttt{W} \to \color{blue}{\texttt{B}}\color{brown}{\underline{\color{red}{\texttt{R}}\color{blue}{\texttt{B}}}}\color{blue}{\texttt{B}}\texttt{W}WWWWW→WWRBW→BRRBW→BRBBW 。这里 W\texttt{W}W 、 R\color{red}{\texttt{R}}R 和 B\color{blue}{\texttt{B}}B 分别表示白色、红色或蓝色单元格,使用戳记的单元格用下划线标记。
给定最终的图片,是否有可能使用零次或多次戳记来制作它?
样例输入
12
5
BRBBW
1
B
2
WB
2
RW
3
BRB
3
RBB
7
WWWWWWW
9
RBWBWRRBW
10
BRBRBRBRRB
12
BBBRWWRRRWBR
10
BRBRBRBRBW
5
RBWBW
样例输出
YES
NO
NO
NO
YES
YES
YES
NO
YES
NO
YES
NO
思路
先按照白色位置W分割,然后单独判断每一小段。
对于每一小段,应该保证长度>=2>=2>=2的同时包含RB两种颜色,否则就是不可行的方案。
代码
n = int(input())
for i in range(n):
a = int(input())
s = input().split("W")
mk = 1
for j in s:
if j == '':
continue
if len(j) == 1:
mk = 0
x, y = 0, 0
for k in j:
if k == 'R':
x += 1
else:
y += 1
if x == 0 or y == 0:
mk = 0
if mk == 0:
print("NO")
else:
print("YES")
E. 2-Letter Strings
题目大意:
给你nnn个只包含两个小写字母的字符串,问满足i<ji < ji<j同时只有一个字母相同的索引 (i,j)(i,j)(i,j) 对的个数。
样例输入
4
6
ab
cb
db
aa
cc
ef
7
aa
bb
cc
ac
ca
bb
aa
4
kk
kk
ab
ab
5
jf
jf
jk
jk
jk
样例输出
5
6
0
6
样例解释
对于第一个测试用例,在一个位置上不同的配对是**(“ab”, “cb”), (“ab”, “db”), (“ab”, “aa”), (“cb”, “db”)** 和 (“cb”, “cc”)。
在第二个测试案例中,有一个位置上不同的配对是**(“aa”, “ac”), (“aa”, “ca”), (“cc”, “ac”), (“cc”, “ca”), (“ac”, “aa”)** 和 (“ca”, “aa”)。
对于第三个测试用例,没有满足条件的配对。
思路
由于字符串长度为222且只包含小写字母,直接创建数组f[i][j]f[i][j]f[i][j]暴力统计所有字符串出现次数。
然后循环分别找第一个位置不同与第二个位置不同的数量加起来。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve() {
int n; cin >> n;
int f[30][30] = {0};
int res = 0;
for(int i = 1; i <= n; i++) {
string s; cin >> s;
for(int j = 0; j <= 25; j++) {
if(j != s[1] - 'a') {
res += f[s[0] - 'a'][j];
}
if(j != s[0] - 'a') {
res += f[j][s[1] - 'a'];
}
}
f[s[0] - 'a'][s[1] - 'a']++;
}
cout << res << endl;
}
signed main() {
int t = 1;
cin >> t;
for(int i = 1; i <= t; i++)
solve();
return 0;
}
F. Eating Candies
题目大意:
一张桌子上从左到右放着 nnn 粒糖果。这些糖果从左到右依次编号。 iii (颗)糖果的重量为 wiw_iwi 。爱丽丝和鲍勃吃糖。
爱丽丝可以从左边开始吃任意数量的糖果(她不能跳着吃,要连续吃)。
鲍勃可以从右边吃任意数量的糖果(他不能跳着吃,要连续吃)。
当然,如果爱丽丝吃了一颗糖,鲍勃就不能吃(反之亦然)。
他们希望公平。他们的目标是吃掉相同总重量的糖果。他们总共能吃多少颗糖果?
样例输入
4
3
10 20 10
6
2 1 4 2 4 1
5
1 2 4 8 16
9
7 3 20 5 15 1 11 8 10
样例输出
2
6
0
7
思路
先用map统计出所有的前缀和与后缀和的出现次数,如果一个数出现了两次,那么说明是可行的方案,我们找到最大的这个数即可。
具体看代码注释。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve() {
int n; cin >> n;
vector<int> l(n), r(n);
for(auto &i : l) cin >> i;
// mp 统计前缀和与后缀出现次数
// L, R 分别统计前后缀和出现位置
map<int, int> mp, L, R;
r[n - 1] = l[n - 1];
mp[r[n - 1]]++, mp[l[0]]++;
R[r[n - 1]] = n - 1, L[l[0]] = 0;
for(int i = n - 2; i >= 0; i--) {
r[i] = r[i + 1] + l[i];
mp[r[i]]++;
R[r[i]] = i;
}
for(int i = 1; i < n; i++) {
l[i] += l[i - 1];
mp[l[i]]++;
L[l[i]] = i;
}
int res = 0;
for(auto &[k, v] : mp) {
// 如果一个数出现次数大于 2 则说明前后缀都有出现
// k * 2 <= r[0] 则保证前后缀没有重叠区间
if(v >= 2 and k * 2 <= r[0]) res = max(res, k);
}
// cout << res << endl;
if(res == 0) cout << "0\n";
else cout << L[res] + 1 + n - R[res] << endl;
}
signed main() {
int t = 1;
cin >> t;
for(int i = 1; i <= t; i++)
solve();
return 0;
}
G. Fall Down
题目大意
网格中有 nnn 行和 mmm 列,以及三种类型的单元格:
- 空单元格,用
.表示。 - 石头,用
*表示。 - 障碍物,用小写拉丁字母
o表示。
所有石子都会往下掉,直到碰到地板(最下面一行)、障碍物或其他已经无法移动的石子。(换句话说,所有的石子只要还能往下掉,就会一直往下掉)。
模拟这一过程。得到的网格是什么样的?
样例输入
3
6 10
.*.*....*.
.*.......*
...o....o.
.*.*....*.
..........
.o......o*
2 9
...***ooo
.*o.*o.*o
5 5
*****
*....
*****
....*
*****
样例输出
..........
...*....*.
.*.o....o.
.*........
.*......**
.o.*....o*
....**ooo
.*o**o.*o
.....
*...*
*****
*****
*****
思路
每一列单独从下往上模拟即可。
- 先找空单元格
- 再往上找石头
- 如果遇到障碍物,就回到第一步
- 如果遇到石头,就跟前面找的空单元格交换位置,再回到第一步
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve() {
int n, m;
cin >> n >> m;
vector<string> v(n);
for(auto &i : v) cin >> i;
for(int j = 0; j < m; j++) {
int x = n - 1, y = j;
while(x >= 0) {
while(x >= 0 and v[x][y] != '.') x--;
// 没找到空单元格,退出循环
if(x < 0) break;
// 记录空单元格位置
int bef = x;
// 再往上找非空单元格
while(x >= 0 and v[x][y] == '.') x--;
// 没找到其他单元格,退出循环
if(x < 0) break;
// 如果找到石头,就交换位置
if(v[x][y] == '*') {
swap(v[bef][y], v[x][y]);
// x 设置为上一个位置继续找
x = bef - 1;
}
}
}
for(auto &i : v) cout << i << endl;
cout << endl;
}
signed main() {
int t = 1;
cin >> t;
for(int i = 1; i <= t; i++)
solve();
return 0;
}
H. Maximal AND
题目大意:
让 AND\mathsf{AND}AND 表示按位与运算, OR\mathsf{OR}OR 表示按位或运算。
给你一个长度为 nnn 的数组 aaa 和一个非负整数 kkk 。你最多可以对数组进行以下类型的 kkk 操作:
- 选择索引 iii ( 1≤i≤n1 \leq i \leq n1≤i≤n ),并将 aia_iai 替换为 ai OR 2ja_i\ \mathsf{OR}\ 2^jai OR 2j 其中 jjj 是 000 和 303030 之间的任意整数。包含。换句话说,在操作中,您可以选择索引 iii ( 1≤i≤n1 \leq i \leq n1≤i≤n ),并将 aia_iai 的 jjj /th 位设置为 111 ( 0≤j≤300 \leq j \leq 300≤j≤30 )。
输出 a1a_1a1 AND\mathsf{AND}AND a2a_2a2 AND\mathsf{AND}AND …\dots… AND\mathsf{AND}AND ana_nan 的最大可能值,最多执行 kkk 次操作。
样例输入
4
3 2
2 1 1
7 0
4 6 6 28 6 6 12
1 30
0
4 4
3 1 3 1
样例输出
2
4
2147483646
1073741825
思路
最后要的结果是所有数字AND\mathsf{AND}AND的结果,ai<231a_i < 2^{31}ai<231,那么结果只要判断二进制的前三十一位。
要想结果二进制的第iii位为111,那么要保证所有数字的第iii位都为111。
我们先统计所有数字二进制第iii位等于111的次数,再从高到低把每一位设置成111即可。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve() {
int n, m;
cin >> n >> m;
// 统计第 i 位为 1 的数量
int f[31] = {0};
for(int i = 1; i <= n; i++) {
int k; cin >> k;
for(int j = 0; j <= 30; j++)
if((k & (1 << j)) > 0)
f[j]++;
}
long long ans = 0;
// 从高到低把每一位设置成 1
for(int i = 30; i >= 0; i--) {
// 如果剩下的操作次数足够把第 i 位设置成 1
if(n - f[i] <= m) {
// 那么答案的第 i 位结果一定为 1
ans |= (1ll << i);
// 减去操作次数
m -= n - f[i];
}
}
cout << ans << endl;
}
signed main() {
int t = 1;
cin >> t;
for(int i = 1; i <= t; i++)
solve();
return 0;
}
Codeforces Round 784 (Div. 4) 题解
953

被折叠的 条评论
为什么被折叠?



