[cf]Codeforces Round #784(Div 4)
由于一次比赛被虐得太惨,,生发开始写blog的想法,于是便有了这篇随笔(找了个近期的cf比赛练练手(bushi))第一次写blog,多多包涵。
第二场cf比赛,第一场打的Div2,被虐太惨,所以第二场挑了个Div4...
比赛链接: https://codeforces.com/contest/1669
A. Division
翻译(参考):
t组样例,每组样例给出一个正整数,判断该整数所在的范围
题解:
签到题,分类讨论下即可
B.Trip
翻译(参考):
t组样例,每组给出一个长度为n的数组,对每组样例输出一个在该数组中出现三次及三次以上的数字(可能有多个,输出任意一个就好),若不存在则输出-1.
题解:
签到题,An<=2e5,值域范围不大,开个数组记录即可(值域过大可以考虑用map记录)。
C. Odd/Even Increments
翻译(参考)
t组样例,对每组样例给出一个长度为n的数组(下标从1开始),有以下两种操作,每种操作可进行任意次
1. 对所有奇数下标的元素+1
2. 对所有偶数下标的元素+1
问是否能进行以上两种操作使得数组所有元素都为奇数或都为偶数
题解:
思维题,很容易想到如果原数组奇数和偶数分别对应的下标不满足均为奇数或者均为偶数不可能经过操作满足条件
故而,分别判断奇数下标是否全为奇或全为偶,偶数下标是否全为奇或全为偶即可。
D. Colorful Stamp
翻译(参考):
t组样例,每组给出一个仅由W R B组成的字符串。问该字符串能否经过操作(选择相邻的两个字符,一个变为R另一个变为B)由全为W的等长字符串得到,若可以输出YES,否则输出NO
题解:
样例解释:
(BRB)
WWW→WRB→BRB(YES)
(RRR)
不可能由WWW得到(NO)
思维题,我们很容易想到每次操作的结果都是一个R一个B,,操作变换有以下四种情况(对W不能进行操作,因为W改变了不可能再变回去)
1. RR ---> RB / BR(减少一个R)
2. BB ---> RB / WR(减少一个W)
3. RB ---> BR
4. BR ---> RB
可以得出结论,只要字串中既含B又含有R就可以得到目标字串
把W看成空格得到一堆字串,判断这些字串中是否全为B或者全为B即可
代码:
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int mod = 1e9 + 7;string s;void solve(){int n, r = 0, b = 0, cnt = 0; // r记录R的个数,b记录B的个数cin >> n;getline(cin, s); //消除换行符getline(cin, s); //读入目标字符串for (int i = 0; i < n; i++){if (s[i] == 'R'){cnt++;r++;}else if (s[i] == 'B'){cnt++;b++;}else //遇到W标志已得到一个子串进行判断该字串是否满足条件{if (r == 0 || b == 0){cout << "NO\n";return;}cnt = 0, r = 0, b = 0;}}if (r == 0 || b == 0) //最后的一个不以W分隔的子串{cout << "NO\n";return;}cout << "YES\n";}signed main(){ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);int __;cin >> __;getline(cin, s);while (__--){solve();}}
翻译(参考):
t组样例,对每组样例给出n个长度为2的仅由abcdefghijk构成的字符串,求有几对字符串满足只有一个对应位置相同。
题解:
样例解释:
7 aa bb cc ac ca bb aa
("aa", "ac"), ("aa", "ca"), ("cc", "ac"), ("cc", "ca"), ("ac", "aa") and ("ca", "aa")
共计6种
可以由容斥原理想到,先分别统计对每种字符在多少个字符串的第一个位置出现和对每种字符在多少个字符串的第二个位置出现的数量减去2*相同的字符串的个数(因为相同的字符串在第一个字符相同和第二个字符相同都有被统计)。利用组合数求出对应的每种情况的个数C2m
代码:
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int mod = 1e9 + 7;string s;void solve(){ll ans = 0;map<char, ll> mp1, mp2; // mp1统计在位置一(s[0])相同的字符串个数,mp2统计在位置二(s[1])相同的字符串个数map<string, ll> mp; //统计相同的字符串个数int n;cin >> n;getline(cin, s); //吸收换行符for (int i = 0; i < n; i++){string ss;getline(cin, ss);if (mp.find(ss) != mp.end()){mp[ss]++;}else{mp[ss] = 1;}if (mp1.find(ss[0]) != mp1.end()){mp1[ss[0]]++;}else{mp1[ss[0]] = 1;}if (mp2.find(ss[1]) != mp2.end()){mp2[ss[1]]++;}else{mp2[ss[1]] = 1;}}for (auto it : mp1) //统计每种字符在位置一相同的字符串的贡献{if (it.second != 1){int t = it.second;ans += (t * (t - 1) / 2);}}for (auto it : mp2) //统计每种字符在位置二相同的字符串的贡献{if (it.second != 1){int t = it.second;ans += (t * (t - 1) / 2);}}for (auto it : mp) //统计每种相同字符串的贡献{if (it.second > 1){int t = it.second;string te = it.first;ans -= 2 * (t * (t - 1) / 2);}}cout << ans << "\n";}signed main(){ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);int __;cin >> __;getline(cin, s);while (__--){solve();}}
翻译(参考):
t组样例,对每组样例给出n个数分别为糖果的价值,Alice从左开始吃糖果,Bob从右往左开始吃糖果,每次只能有一个人吃到糖果,问是否能有一种方案使得两人在中途吃到的糖果总数量相同,输出最大糖果数量
题解:
样例解释:
9
7 3 20 5 15 1 11 8 10
Alice : [7,3,20]
Bob : [10,8,11,1]
两人吃的总价值均为30
可以吃的最多的糖果数量为7个
笔者认为此题考查了前缀和,后缀和,二分。前缀和维护Alice吃的糖果总价值,后缀和维护Bob吃的糖果的总价值,二分查找前缀和对应的元素在后缀和数组中的位置,若出现可更新结果(Alice和Bob的总价值相同),对结果取max输出即可
代码:
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int mod = 1e9 + 7;ll w[200009], a[200009], b[200009]; //记得开long long,因为前缀和或后缀和可能很大会爆intvoid solve(){int n, ans = 0;cin >> n;for (int i = 1; i <= n; i++){cin >> w[i];a[i] = a[i - 1] + w[i]; //前缀和->Alice的总价值}b[n + 1] = 0;for (int i = n; i >= 1; i--){b[i] = b[i + 1] + w[i]; //后缀和->Bob的总价值}for (int r = n; r > 1; r--){int p = lower_bound(a + 1, a + 1 + r - 1, b[r]) - a; //二分查找if (p != r && a[p] == b[r]) //找到的位置值相同,更新答案{ans = max(ans, p + n - r + 1); // Alice:p个 Bob:n-r+1个}}cout << ans << "\n";}signed main(){ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);int __;cin >> __;while (__--){solve();}}
翻译(参考):
t组样例,对每组样例给出n*m的地图,‘*’代表石头,‘.’代表空地,‘o’代表障碍,对每个石头可以进行下落直到遇到障碍或到达底部,输出最终的地图。
样例:
6 10
.*.*....*.
.*.......*
...o....o.
.*.*....*.
..........
.o......o*
输出:
..........
...*....*.
.*.o....o.
.*........
.*......**
.o.*....o*
题解:
对每个*(石头)往下找第一个不为.(空地)的位置或已到达底部,将二者进行交换即可
代码:
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int mod = 1e9 + 7;void solve(){int n, m;cin >> n >> m;char s[60][60];for (int i = 0; i < n; i++){for (int j = 0; j < m; j++){cin >> s[i][j]; //读入}}for (int i = n - 2; i >= 0; i--){for (int j = 0; j < m; j++){if (s[i][j] == '*') //石头{int k = i + 1;while (k < n && s[k][j] == '.') //找第一个不为空地的位置或已到达底部{k++;}swap(s[i][j], s[k - 1][j]); //交换}}}for (int i = 0; i < n; i++){for (int j = 0; j < m; j++){cout << s[i][j];}cout << "\n";}cout << "\n";}signed main(){ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);int __;cin >> __;while (__--){solve();}}