【cf比赛记录】Codeforces Round #604 (Div. 2)
感觉这场是最近以来做过的最顺手的一场,持续上分,开心w
A了 前三题,然后第四题其实还有半个多小时,但怕身体撑不住,就先退了,其实第四题也很简单
自己认为的算法标签:
A.暴力模拟、字符串
B.数学、构造、排序
C.贪心、构造
D.构造、遍历
😄
A. Beautiful String
// https://codeforces.com/contest/1265/problem/A
/*
要求:不能有连续相同的字符,然后把'?'改为'a' || 'b' || 'c',使最终字符串符合要求
如果不满足就 '-1'
-1 好办 ---- 如果原字符串里就不符合就为 -1
我的做法是暴力模拟 ( 暴力的意思是代码有点长...然后自己 wa 了两发 tcl )
*/
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
int T;
string a;
bool A, B, C;
int main()
{
cin >> T;
while(T--){
cin >> a;
A = B = C = false;
bool ok = true; // 判断是否 -1
int j = 0;
for(int i = 1; i < a.size(); i++){
if(a[i] == a[i - 1] && a[i] != '?'){
ok = false; // 是 -1
break;
}
}
if(a.size() > 1 && ok){ // 长度超过 1 且 原字符串没有问题的情况
// 特判第一位
if(a[0] == '?'){
if(a[1] == 'a') A = true;
else if(a[1] == 'b') B = true;
else if(a[1] == 'c') C = true;
else if(a[1] == '?') a[0] = 'a';
if(A) a[0] = 'b';
else if(B) a[0] = 'c';
else if(C) a[0] = 'a';
}
A = B = C = false;
// 特判最后一位
if(a[a.size() - 1] == '?'){
if(a[a.size() - 2] == 'a') A = true;
else if(a[a.size() - 2] == 'b') B = true;
else if(a[a.size() - 2] == 'c') C = true;
else if(a[a.size() - 2] == '?') a[a.size() - 1] = 'a';
if(A) a[a.size() - 1] = 'b';
else if(B) a[a.size() - 1] = 'c';
else if(C) a[a.size() - 1] = 'a';
}
for(int i = 1; i < a.size() - 1; i++){ // 对 (1, size() - 1) 开始暴力搜索
A = B = C = false; // 记录前后出现了哪个字符
if(a[i - 1] == 'a') A = true;
else if(a[i - 1] == 'b') B = true;
else if(a[i - 1] == 'c') C = true;
if(a[i + 1] == 'a') A = true;
else if(a[i + 1] == 'b') B = true;
else if(a[i + 1] == 'c') C = true;
if(a[i] == '?'){ // 只需要改 '?'
if(A && B) a[i] = 'c';
else if(A && C) a[i] = 'b';
else if(B && C) a[i] = 'a';
else if(A) a[i] = 'b';
else if(B) a[i] = 'c';
else if(C) a[i] = 'a';
}
}
}
else if(a[0] == '?') a[0] = 'a'; // 字符串长度为 1 的情况 且是 "?"
if(ok) cout << a << endl;
else cout << -1 << endl;
}
return 0;
}
B.Beautiful Numbers
// https://codeforces.com/contest/1265/problem/B
/*
题意是要找 在一个区间 [l, r] 的数据是否有序 (从 1 开始)
结果是判断区间长度为 1 ~ n 是否满足要求
既然是从 1 开始 如果满足条件 区间的长度必然等于区间数组里的[位置] 最大值 - 最小值 + 1
根据这个结论就可以解决了
样例一:
排序前:
数值 4 5 1 3 2 6
位置 1 2 3 4 5 6
排序后:
数值 1 2 3 4 5 6
位置 3 5 4 1 2 6
区间长度为 3 时
数值 [ 1 2 3 ] 4 5 6
位置 [ 3 5 4 ] 1 2 6
位置最大值 - 位置最小值 + 1 = 5 - 3 + 1 = 3 等于区间长度 3
所以区间长度为 3 时可行
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
using namespace std;
struct node{
int num, pla;
}mem[200005];
int T, n;
bool cmp(node a, node b){
return a.num < b.num;
}
int main()
{
scanf("%d", &T);
while(T--){
string ans;
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d", &mem[i].num);
mem[i].pla = i; // 记录位置
}
sort(mem + 1, mem + 1 + n, cmp); // 把数据从 1 ~ n 升序排序
int minn = n, maxx = 1;
for(int i = 1; i <= n; i++){ // i 的大小等同于 区间的大小
// printf("num:%d pla:%d\n", mem[i].num, mem[i].pla);
// 更新当前区间里位置的最大最小值
if(mem[i].pla < minn) minn = mem[i].pla;
if(mem[i].pla > maxx) maxx = mem[i].pla;
// 判断
if(maxx - minn + 1 == i) ans += '1';
else ans += '0';
}
cout << ans << endl; // 用 string 输出
}
return 0;
}
C.Beautiful Regional Contest
// https://codeforces.com/contest/1265/problem/C
/*
贪心构造问题吧
条件很多,但也很好利用
1.获奖人数最多只有参赛人数的一半
2.金牌的A题数 > 银牌的A题数 > 铜牌的A题数
3.金牌的得奖数 < 银牌的, 铜牌的 (银牌与铜牌的多少没有要求)
把 A 题最多的一组人授予金牌
然后先依次给后面的人银牌,当银牌数比金牌数多时,剩下的都给铜牌 (这样容易避免铜牌数为 0 的情况)
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int T, n, cnt, a, x, y, z;
int mem[1000006];
int que[1000006];
bool cmp(int a, int b) { return a > b; }
int main()
{
scanf("%d", &T);
while(T--){
// 初始化
x = y = z = 0;
for(int i = 0; i < cnt; i++){
mem[que[i]] = 0;
}
cnt = 0;
scanf("%d", &n);
for(int i = 0; i < n; i++){
scanf("%d", &a);
if(mem[a] == 0){
que[cnt++] = a; // 类似 set
}
mem[a]++; // 桶排
}
// sort(que, que + cnt, cmp); // 因为题目就有降序输入,就不用 sort 了
bool ok = true;
int tot = n / 2; // 可以获奖的总人数 1
x = mem[que[0]]; // 获得金牌的人数
int last = tot - x; // 剩下银牌和铜牌最多的总数
bool Z = false;
for(int i = 1; i < cnt && last > 0; i++){
// printf("x:%d y:%d z:%d last:%d\n", x, y, z, last);
if(last < mem[que[i]]) break; // 当前组的人数比可给奖牌人数多时,就不能给了 (见样例 5)
if(!Z){ // 开关 false 给银牌; true 给铜牌
y += mem[que[i]];
if(y > x){ // 银牌一旦符合了条件就给铜牌加
Z = true;
}
}
else {
z += mem[que[i]];
}
last -= mem[que[i]];
}
if(x >= y || x >= z) ok = false; // 判断是否符合条件
if(ok) printf("%d %d %d\n", x, y, z);
else printf("0 0 0\n");
}
return 0;
}
D.Beautiful Sequence
// https://codeforces.com/contest/1265/problem/D
/*
感觉像是遍历的思维构造题 有思路就很好做的
可以把该题想象成过山车或者山峰......
*/
#include<iostream>
#include<cstdio>
using namespace std;
int n;
int cnt[5], last[5]; // last 是记录当前还有多少 0, 1, 2, 3
int ans[100005];
bool ok;
int main()
{
for(int i = 0; i < 4; i++) {
scanf("%d", &cnt[i]);
n += cnt[i]; // n 就是输出的总长度
}
for(int i = 0; i < 4; i++){
if(!cnt[i]) continue;
ans[1] = i; // 依次取 0, 1, 2, 3 为第一位开始
ok = true;
for(int j = 0; j < 4; j++){
last[j] = cnt[j] - (i == j); // 初始化 last
}
for(int j = 2; j <= n; j++){ // 因为第一位已经放了所以从第二位开始
int p = ans[j - 1];
if(p - 1 >= 0 && last[p - 1]) { // 往小(低)处走
ans[j] = p - 1; last[p - 1]--;
}
else if(p + 1 < 4 && last[p + 1]){ // 往大(高)处走
ans[j] = p + 1; last[p + 1]--;
}
else ok = false; // 假如都不能 则当前做法不可取
}
if(ok){
printf("YES\n");
for(int i = 1; i <= n; i++){
printf("%d%c", ans[i], i == n ? '\n' : ' ');
}
break;
}
}
if(!ok) printf("NO\n");
return 0;
}
记录菜鸟的成长: