【Codeforces Round #784 (Div. 4)】【AK题解】
2022年4月30日19:43:21
文章目录
- 2022年4月30日19:43:21
A. Division?
题目描述
Codeforces将其用户按其rating分为4个部门。
第1区: 1900 ≤ r a t i n g 1900≤rating 1900≤rating
第2区: 1600 ≤ r a t i n g ≤ 1899 1600≤rating≤1899 1600≤rating≤1899
第3区: 1400 ≤ r a t i n g ≤ 1599 1400≤rating≤1599 1400≤rating≤1599
第4区: r a t i n g ≤ 1399 rating≤1399 rating≤1399
给出一个评级,打印该评级属于哪个部门。
输入
输入的第一行包含一个整数 t ( 1 ≤ t ≤ 1 0 4 t(1≤t≤10^4 t(1≤t≤104)–测试案例的数量。
每个测试的描述由一行组成,包含一个整数等级( − 5000 ≤ r a t i n g ≤ 5000 -5000≤ rating ≤5000 −5000≤rating≤5000)。
输出
对于每个测试案例,输出一行包含正确的 d i v i s i o n division division,格式为 “ D i v i s i o n Division Division X X X”,其中X是 1 到 4 之间的整数,代表相应评级的除法。
测试样例
input
7
-789
1299
1300
1399
1400
1679
2300
output
Division 4
Division 4
Division 4
Division 4
Division 3
Division 2
Division 1
题解
#includeusing namespace std;typedef long long ll;typedef long double ld;typedef pair<int,int> pii;const int inf=0x3f3f3f3f;const int maxn=1e6+5;void solve(){ int n; cin >> n; if(n<=1399){ cout << "Division 4\n"; }else if(n<=1599){ cout << "Division 3\n"; }else if(n<=1899){ cout << "Division 2\n"; }else{ cout << "Division 1\n"; }}int main(){ ios::sync_with_stdio(0); int t; cin>>t; while(t--) solve(); return 0;}
B. Triple
题目描述
给定一个包含 n 个元素的数组 a,打印至少出现 3 次的任何值,如果没有这样的值,则打印 -1。
输入
第一行包含一个整数 t ( 1 ≤ t ≤ 1 0 4 ) t (1≤t≤10^4) t(1≤t≤104)——测试用例的数量。
每个测试用例的第一行包含一个整数 n ( 1 ≤ n ≤ 2 ⋅ 1 0 5 ) n (1≤n≤2⋅10^5) n(1≤n≤2⋅105) — 数组的长度。
每个测试用例的第二行包含 n n n 个整数 a 1 , a 2 , . . . , a n ( 1 ≤ a i ≤ n ) a_1,a_2,...,a_n (1≤a_i≤n) a1,a2,...,an(1≤ai≤n) — 数组的元素。
保证所有测试用例的 n n n 之和不超过 2 ⋅ 1 0 5 2⋅10^5 2⋅105。
输出
对于每个测试用例,打印至少出现 3 次的任何值,如果没有这样的值,则打印 -1。
测试样例
input
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
output
-1
2
2
4
3
-1
4
题解
#includeusing namespace std;typedef long long ll;typedef long double ld;typedef pair<int,int> pii;const int inf=0x3f3f3f3f;const int maxn=2e5+5;void solve(){ int n; cin >> n; int a[maxn] = {0}; for (int i = 0; i < n;i++){ cin >> a[i]; } sort(a, a + n); int t = a[0]; int cnt = 1; int flag = 1; for (int i = 1; i < n; i++){ if(a[i]==t){ cnt++; if(cnt>=3){ cout << a[i] << "\n"; flag = 0; break; } }else{ t = a[i]; cnt = 1; } } if(flag){ cout << "-1\n"; }}int main(){ ios::sync_with_stdio(0); int t; cin>>t; while(t--) solve(); return 0;}
C. Odd/Even Increments
题目描述
给定一个包含 n n n 个正整数的数组 a = [ a 1 , a 2 , … , a n ] a=[a1,a2,…,an] a=[a1,a2,…,an],您可以对其进行两种类型的运算:
将 1 1 1 添加到具有奇数索引的每个元素。换句话说,将数组更改如下: a 1 : = a 1 + 1 , a 3 : = a 3 + 1 , a 5 : = a 5 + 1 , . . . a_1:=a_1+1,a_3:=a_3+1,a_5:=a_5+1,... a1:=a1+1,a3:=a3+1,a5:=a5+1,...。
将 1 1 1 添加到具有偶数索引的每个元素。换句话说,将数组更改如下: a 2 : = a 2 + 1 , a 4 : = a 4 + 1 , a 6 : = a 6 + 1 , . . . a_2:=a_2+1,a_4:=a_4+1,a_6:=a_6+1,... a2:=a2+1,a4:=a4+1,a6:=a6+1,...。
确定经过任意次数的操作后,是否有可能使最终数组仅包含偶数或仅包含奇数。换句话说,确定是否可以使数组的所有元素在经过任意次数的操作后具有相同的奇偶性。
请注意,您可以多次执行这两种类型的操作(甚至没有)。不同类型的操作可以执行不同的次数。
输入
第一行包含一个整数 t ( 1 ≤ t ≤ 100 ) t (1≤t≤100) t(1≤t≤100)——测试用例的数量。
每个测试用例的第一行包含一个整数 n ( 2 ≤ n ≤ 50 ) n (2≤n≤50) n(2≤n≤50) — 数组的长度。
每个测试用例的第二行包含 n n n 个整数 a 1 , a 2 , … , a n ( 1 ≤ a i ≤ 1 0 3 ) a_1,a_2,…,a_n (1≤a_i≤10^3) a1,a2,…,an(1≤ai≤103) — 数组的元素。
请注意,执行操作后,数组中的元素可能会大于 1 0 3 10^3 103。
输出
输出 t 行,每行包含对应测试用例的答案。作为答案,如果经过任意次数的操作后可以使最终数组仅包含偶数或奇数,则输出“YES”,否则输出“NO”。
您可以在任何情况下输出答案(例如,字符串“yEs”、“yes”、“Yes”和“YES”将被识别为肯定答案)。
测试样例
input
4
3
1 2 1
4
2 2 2 3
4
2 2 2 2
5
1000 1 1000 1 1000
output
YES
NO
YES
YES
题解
#includeusing namespace std;typedef long long ll;typedef long double ld;typedef pair<int,int> pii;const int inf=0x3f3f3f3f;const int maxn=1e6+5;void solve(){ int n; cin >> n; int a[100] = {0}; for (int i = 0; i < n;i++){ cin >> a[i]; } int flag1 = 1;//1奇数 int flag2 = 1;//2奇数 int flag = 1;//yes if(n==2){ cout << "YES\n"; }else{ if(a[0]%2==0) flag1 = 0; if(a[1]%2==0) flag2 = 0; for (int i = 2; i < n;i+=2){ if(a[i]%2==0&&!flag1||(a[i]%2!=0&&flag1)){ continue; }else{ flag = 0; break; } } for (int i = 1; i < n;i+=2){ if(a[i]%2==0&&!flag2||(a[i]%2!=0&&flag2)){ continue; }else{ flag = 0; break; } } if(flag) cout << "YES\n"; else cout << "NO\n"; }}int main(){ ios::sync_with_stdio(0); int t; cin>>t; while(t--) solve(); return 0;}
D. Colorful Stamp
题目描述
给定一行 n 个单元格,最初都是白色的。使用印章,您可以标记任意两个相邻的单元格,使一个变为红色,另一个变为蓝色。印章可以旋转,即它可以以两种方式使用:BR
和 RB
。
在使用过程中,印章必须完全适合给定的 n 个单元格(不能部分位于单元格之外)。印章可以多次应用于同一个单元格。印章的每次使用都会重新着色印章下方的两个单元格。
例如,制作图片 BRBBW
的一种可能的印章序列可能是 WWWWW
→WWRBW
→BRRBW
→BRBBW
。这里 W、R 和 B 分别代表一个白色、红色或蓝色的单元格,并且使用邮票的单元格用下划线标记。
给定最终图片,是否有可能使用邮票零次或多次?
输入
第一行包含一个整数 t ( 1 ≤ t ≤ 1 0 4 ) t (1≤t≤10^4) t(1≤t≤104)——测试用例的数量。
每个测试用例的第一行包含一个整数 n ( 1 ≤ n ≤ 1 0 5 ) n (1≤n≤10^5) n(1≤n≤105)——图片的长度。
每个测试用例的第二行包含一个字符串 s——你需要制作的图片。保证 s 的长度为 n,并且 s 仅由字符 W、R 和 B 组成,分别代表白色、红色或蓝色单元格。
保证所有测试用例的 n 总和不超过 105。
输出
输出 t 行,每行包含对应测试用例的答案。作为回答,如果可以使用该图章零次或多次制作图片,则输出“YES”,否则输出“NO”。
您可以在任何情况下输出答案(例如,字符串“yEs”、“yes”、“Yes”和“YES”将被识别为肯定答案)。
测试样例
input
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
output
YES
NO
NO
NO
YES
YES
YES
NO
YES
NO
YES
NO
题解
#includeusing namespace std;typedef long long ll;typedef long double ld;typedef pair<int,int> pii;const int inf=0x3f3f3f3f;const int maxn=1e6+5;void solve(){ int n; cin >> n; string s; cin >> s; int cnt1 = 0, cnt2 = 0, flag = 1; for (int i = 0; i < n;i++){ if(s[i]=='W'){ if((!cnt1&&cnt2)||(cnt1&&!cnt2)){ cout << "no\n"; flag = 0; return; } cnt1 = 0; cnt2 = 0; } else if(s[i]=='R') cnt1++; else if(s[i]=='B') cnt2++; if(i==n-1){ if((!cnt1&&cnt2)||(cnt1&&!cnt2)){ cout << "no\n"; flag = 0; } } } if(flag) cout << "yes\n";}int main(){ ios::sync_with_stdio(0); int t; cin>>t; while(t--) solve(); return 0;}
E. 2-Letter Strings
题目描述
给定 n 个字符串,每个长度为 2,由从“a”到“k”的小写拉丁字母组成,输出索引对 ( i , j ) (i,j) (i,j) 的数量,使得 i < j i<j i<j 和第 i i i 个字符串和第 j j j 个字符串在一个位置上完全不同。
换句话说,计算对 ( i , j ) ( i < j ) (i,j) (i<j) (i,j)(i<j) 的数量,使得第 i i i 个字符串和第 j j j 个字符串恰好有一个位置 p (1≤p≤2),使得 sip ≠ sjp s_{ip}≠s_{jp} sip=sjp。
答案可能不适合 32 位整数类型,因此您应该使用 64 位整数,如 C++ 中的 long long 以避免整数溢出。
输入
输入的第一行包含一个整数 t ( 1 ≤ t ≤ 100 ) t (1≤t≤100) t(1≤t≤100) — 测试用例的数量。测试用例的描述如下。
每个测试用例的第一行包含一个整数 n ( 1 ≤ n ≤ 1 0 5 ) n (1≤n≤10^5) n(1≤n≤105) — 字符串的数量。
然后是 n n n 行,其中第 i i i 行包含长度为 2 2 2 的单个字符串 s i s_i si,由从“a”到“k”的小写拉丁字母组成。
保证所有测试用例的 n 总和不超过 1 0 5 10^5 105。
输出
对于每个测试用例,打印一个整数 — ( i , j ) ( i < j ) (i,j) (i<j) (i,j)(i<j) 对的数量,使得第 i i i 个字符串和第 j j j 个字符串恰好有一个位置 p ( 1 ≤ p ≤ 2 ) p (1≤p≤2) p(1≤p≤2),例如 sip ≠ sjp s_{ip}≠s_{jp} sip=sjp。
请注意,某些测试用例的答案不适合 32 位整数类型,因此您应该在编程语言中使用至少 64 位整数类型(如 C++ 的 long long)。
测试样例
input
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
output
5
6
0
6
题解
一种解决方案是遍历所有给定的字符串,生成所有在一个位置上完全不同的字符串,并计算这些字符串在数组中出现的次数。
O ( n l o g n ) O(nlogn) O(nlogn) 或 O ( n ) O(n) O(n)
#includeusing namespace std;typedef long long ll;typedef long double ld;typedef pair<int,int> pii;const int inf=0x3f3f3f3f;const int maxn=1e6+5;ll n;string a[maxn]; void solve() { cin >> n; map<string, ll> us; map<ll, ll> used; map<ll, ll> uss; for(int i = 1;i <= n;i++) { cin >> a[i]; } ll ans = 0; for(int i = 1;i <= n;i++) { ans += (used[a[i][0]] - us[a[i]]); ans += (uss[a[i][1]] - us[a[i]]); us[a[i]]++; used[a[i][0]]++; uss[a[i][1]]++; } cout << ans << "\n";}int main(){ ios::sync_with_stdio(0); int t; cin>>t; while(t--) solve(); return 0;}
F. Eating Candies
题目描述
桌子上从左到右有 n 颗糖果。糖果从左到右编号。第 i 个糖果的重量为 w。爱丽丝和鲍勃吃糖果。
Alice 可以从左边吃任意数量的糖果(她不能跳过糖果,她会连续吃掉它们)。
Bob 可以从右边吃任意数量的糖果(他不能跳过糖果,他会连续吃掉它们)。
当然,如果 Alice 吃了糖果,Bob 就不能吃(反之亦然)。
他们想要公平。他们的目标是吃相同重量的糖果。他们总共可以吃多少糖果?
输入
第一行包含一个整数 t ( 1 ≤ t ≤ 1 0 4 ) t (1≤t≤10^4) t(1≤t≤104)——测试用例的数量。
每个测试用例的第一行包含一个整数 n ( 1 ≤ n ≤ 2 ⋅ 1 0 5 ) n (1≤n≤2⋅10^5) n(1≤n≤2⋅105)——桌子上糖果的数量。
每个测试用例的第二行包含 n n n 个整数 w 1 , w 2 , … , w n ( 1 ≤ w i ≤ 1 0 4 ) w_1,w_2,…,w_n (1≤w_i≤10^4) w1,w2,…,wn(1≤wi≤104)——糖果的重量从左到右。
保证所有测试用例的 n n n 之和不超过 2 ⋅ 1 0 5 2⋅10^5 2⋅105。
输出
对于每个测试用例,打印一个整数——Alice 和 Bob 在满足条件的情况下总共可以吃的糖果的最大数量。
测试样例
input
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
output
2
6
0
7
题解
我们可以用双指针技术解决这个问题。 令 l l l 为左指针,初始为 1 1 1, r r r 为右指针,初始为 n n n。 让我们将 Alice 和 Bob 的当前总数存储为 a a a 和 b b b 。
让我们从左到右迭代 l l l 。 对于每个 l l l,我们应该执行以下操作。
- a a a 增加 al a_l al(爱丽丝吃了第 l l l 个糖果)。
- 向左移动 r r r 直到 Bob 的总数至少是 Alice 的总数,并且每次我们移动时更新 b b b。
- 如果两个指针交叉,那么 Alice 和 Bob 都拿了相同的糖果,这是不可能的。 所以我们应该退出并输出当前的答案。
- 否则,如果在这一步之后
a==b
,我们应该将当前答案更新为等于 Alice 和 Bob 的值。
l l l 和 r r r 总共最多移动 n n n 次,因此解决方案在 O ( n ) O(n) O(n) 中运行。
#includeusing namespace std;typedef long long ll;typedef long double ld;typedef pair<int,int> pii;const int inf=0x3f3f3f3f;const int maxn=2e5+5;void solve(){ int n; cin >> n; int a[maxn] = {0}; for (int i = 0; i < n;i++){ cin >> a[i]; } int sum1 = a[0]; int sum2 = a[n-1]; int ans = 0; int l = 0, r = n - 1; while(l < r){ if(sum1<sum2){ l++; sum1 += a[l]; }else if(sum1>sum2){ r--; sum2 += a[r]; }else{ ans = l + 1 + n - r; l++; r--; sum1 += a[l]; sum2 += a[r]; } } cout << ans << endl;}int main(){ ios::sync_with_stdio(0); int t; cin>>t; while(t--) solve(); return 0;}
G. Fall Down
题目描述
有一个 n n n 行 m m m 列的网格,以及三种类型的单元格:
- 一个空单元格,用“
.
”表示。 - 一块石头,用“
*
”表示。 - 障碍物,用小写拉丁字母“
o
”表示。
所有的石头都掉下来,直到碰到地板(最下面一排)、障碍物或其他已经不动的石头。 (换句话说,所有的石头只要能掉下来就掉下来。)
模拟过程。生成的网格是什么样的?
输入
输入由多个测试用例组成。第一行包含一个整数 t ( 1 ≤ t ≤ 100 ) t (1≤t≤100) t(1≤t≤100)——测试用例的数量。测试用例的描述如下。
每个测试用例的第一行包含两个整数 n n n 和 m ( 1 ≤ n , m ≤ 50 ) m (1≤n,m≤50) m(1≤n,m≤50)——分别是网格中的行数和列数。
然后是 n n n 行,每行包含 m m m 个字符。这些字符中的每一个都是“.
”、“*
”或“o
”——分别是空单元、石头或障碍物。
输出
对于每个测试用例,输出一个 n n n 行 m m m 列的网格,显示过程的结果。
您不需要在每次测试后输出一个新行,它在示例中只是为了清楚起见。
测试样例
input36 10.*.*....*..*.......*...o....o..*.*....*............o......o*2 9...***ooo.*o.*o.*o5 5******....*****....******output.............*....*..*.o....o..*.........*......**.o.*....o*....**ooo.*o**o.*o.....*...****************
题解
列之间不会相互影响,因此我们可以自行求解每一列。
对于每一列,从底部到顶部,并跟踪最后看到的障碍物所在的行; 叫它 last
。 请注意,最初,last = n+1
,因为我们将地板视为第 n+1
排障碍物。 每当我们看到一个新的障碍,应该更新last
。
现在,如果我们看到一块石头,我们应该把它移到 last-1
行,因为它会比最后看到的障碍物高一排(它会落在它上面)。 之后,我们也应该将 last
减 1,因为如果任何未来的石头落在它上面,它们会落在这块石头上面的那排。
#include using namespace std;typedef long long ll;typedef long double ld;typedef pair<int, int> pii;const int inf = 0x3f3f3f3f;const int maxn = 1e6 + 5;void solve(){ int n, m;cin >> n >> m;char g[n + 7][m + 7];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {cin >> g[i][j];}}for (int j = 0; j < m; j++) {int last = n - 1;for (int i = n - 1; i >= 0; i--) {if (g[i][j] == 'o') {last = i - 1;}else if (g[i][j] == '*') {swap(g[i][j], g[last][j]); last--;}}}for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {cout << g[i][j];}cout << '\n';}}int main(){ ios::sync_with_stdio(0); int t; cin >> t; while (t--) solve(); return 0;}
H. Maximal AND
题目描述
令 AND
表示按位与运算,OR
表示按位或运算。
给定一个长度为 n n n 的数组 a a a 和一个非负整数 k k k。您最多可以对以下类型的数组执行 k k k 个操作:
选择一个索引 i ( 1 ≤ i ≤ n ) i (1≤i≤n) i(1≤i≤n) 并将 a i a_i ai 替换为 a i a_i ai OR 2 j 2^j 2j 其中 j j j 是 0 0 0 到 30 30 30 之间的任何整数(包括 0 0 0 到 30 30 30)。换句话说,在一个操作中,您可以选择一个索引 i ( 1 ≤ i ≤ n ) i (1≤i≤n) i(1≤i≤n) 并将 a i a_i ai 的第 j j j 位设置为 1 ( 0 ≤ j ≤ 30 ) 1 (0≤j≤30) 1(0≤j≤30)。
在执行最多 k 次操作后,输出 a 1 a_1 a1 AND a 2 a_2 a2 AND . . . ... ... AND a n a_n an 的最大可能值。
输入
输入的第一行包含一个整数 t ( 1 ≤ t ≤ 100 ) t (1≤t≤100) t(1≤t≤100) — 测试用例的数量。测试用例的描述如下。
每个测试用例的第一行包含整数 n n n 和 k ( 1 ≤ n ≤ 2 ⋅ 1 0 5 , 0 ≤ k ≤ 1 0 9 ) k (1≤n≤2⋅10^5, 0≤k≤10^9) k(1≤n≤2⋅105,0≤k≤109)。
然后是一行,包含描述数组 a ( 0 ≤ a i < 2 31 ) a (0≤ai<2^{31}) a(0≤ai<231) 的 n n n 个整数。
保证所有测试用例的 n n n 之和不超过 2 ⋅ 1 0 5 2⋅10^5 2⋅105。
输出
对于每个测试用例,在执行最多 k 个操作后,单行输出包含 a 1 a_1 a1 AND a 2 a_2 a2 AND . . . ... ... AND a n a_n an 的最大可能值。
测试样例
input
4
3 2
2 1 1
7 0
4 6 6 28 6 6 12
1 30
0
4 4
3 1 3 1
output
2
4
2147483646
1073741825
题解
最佳策略是贪心,取我们有足够操作在每个数组元素中设置的最高位。 为此,我们为每个位维护一个计数,其中包含已经设置它的元素的数量。 设置第 i i i 位的成本将是 n − c o u n t i n − count_i n−counti。
我们从最高位到最低位:
- 如果我们还有足够的操作,置于当前位,减去它的成本,然后移动到下一个较低的位。
- 如果我们没有足够的操作,当前位不修改并且继续下一个较低的位。
一旦我们处理了位 0,我们就会停止。
时间复杂度为 O ( n l o g a i ) O(nloga_i) O(nlogai)。
#include using namespace std;typedef long long ll;typedef long double ld;typedef pair<int, int> pii;const int inf = 0x3f3f3f3f;const int maxn = 1e6 + 5;void solve(){ int t; cin >> t; while(t--) { int n, k; cin >> n >> k; vector<int> cnt(31, 0), a(n); for(int i = 0;i < n; ++i) { cin >> a[i]; for(int j = 30; j >= 0; --j) { if(a[i] & (1 << j)) ++cnt[j]; } } int ans = 0; for(int i = 30; i >= 0; --i) { int need = n - cnt[i]; if(need <= k) { k -= need; ans += (1 << i); } } cout << ans << "\n";}int main(){ ios::sync_with_stdio(0); int t; cin >> t; while (t--) solve(); return 0;}