比赛链接:
https://codeforces.com/contest/1536
A. Omkar and Bad Story
题目大意:
当一个序列任意两个数之差的绝对值都在这个序列中出现时,称这个序列是 \(nice\) 的,先给定一个序列 \(a\),让你添加元素使该序列 \(nice\),若不能实现,输出 \(no\),能实现则输出添加元素后的序列。
思路:
容易知道,当序列中有负数时,序列永远不可能 \(nice\),因为序列中任意一个数减去这个负数后会变大,那么序列就会无限地扩张下去。
当序列中没有负数的时候,我们可以将序列空缺的值全部补上,这样子任意元素之差都会在序列中出现了。
代码:
#include <bits/stdc++.h>
using namespace std;
int T, n, a[110];
void solve(){
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
sort (a + 1, a + n + 1);
if (a[1] < 0) cout << "NO\n";
else {
cout << "YES\n" << a[n] + 1 << "\n";
for (int i = 0; i <= a[n]; i++)
cout << i << " \n"[i == a[n]];
}
}
int main(){
cin >> T;
while (T--)
solve();
return 0;
}
B. Prinzessin der Verurteilung
题目大意:
定义一个字符串的 \(mex\) 为字符串中未出现的最短的字符串,给定一个字符串,找到它的 \(mex\)。
思路:
因为给定的字符串长度最长为 1000,所以直接暴力枚举长度小于 3 的所有字符串,找到不存在的字符串然后输出。
代码:
#include <bits/stdc++.h>
using namespace std;
int T, n;
string s;
void solve(){
cin >> n >> s;
for (int i = 0; i < 26; i++){
int c = 0;
for (int p = 0; p < n; p++){
if (s[p] - 'a' == i){
c = 1;
break;
}
}
if (c == 0){
cout << char(i + 'a') << "\n";
return;
}
}
for (int i = 0; i < 26; i++)
for (int j = 0; j < 26; j++){
int c = 0;
for (int p = 1; p < n; p++){
if (s[p] - 'a' == j && s[p - 1] - 'a' == i){
c = 1;
break;
}
}
if (c == 0){
cout << char(i + 'a') << char(j + 'a') << "\n";
return;
}
}
for (int i = 0; i < 26; i++)
for (int j = 0; j < 26; j++)
for (int k = 0; k < 26; k++){
int c = 0;
for (int p = 2; p < n; p++){
if (s[p] - 'a' == k && s[p - 1] - 'a' == j && s[p - 2] - 'a' == i){
c = 1;
break;
}
}
if (c == 0){
cout << char(i + 'a') << char(j + 'a') << char(k + 'a') << "\n";
return;
}
}
}
int main(){
cin >> T;
while (T--)
solve();
return 0;
}
C. Diluc and Kaeya
题目大意:
给一个只包含 'K' 和 'D' 的字符串,可以对它进行一个划分,但要使每段 'K' 和 'D' 的比例都相同,输出该字符串每一个前缀最多能划分成几段。
思路:
求出每一个前缀中 'K' 和 'D' 的比例,然后将结果记录下来,因为要划分该字符串,所以划分最多段的方案中每段的比例一定和当前字符串的比例一样的,所以当前字符串最多能划分的段数就是当前 'K' 和 'D' 的比例结果在前面所有前缀中出现的总次数。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
int T, n, a, b;
string s;
void solve(){
cin >> n >> s;
a = 0, b = 0;
map <pair<int, int>, int> mp;
for (int i = 0; i < n; ++ i){
if (s[i] == 'D') a++;
else b++;
int g = __gcd(a, b);
pair <int, int> p = make_pair(a / g, b / g);
mp[p]++;
cout << mp[p] << " \n"[i == n - 1];
}
}
int main(){
cin >> T;
while (T--)
solve();
return 0;
}
D. Omkar and Medians
题目大意:
定义 \(b_i\) 为 \(a_1,a_2,...,a_{2 * i - 1}\) 的中位数,现给定长度为 \(n\) 的序列 \(b\),判断有没有序列 \(a\) 能符合要求,输出 "YES" 或 "NO"。
思路:
添加一个数进入序列 \(b\),就会添加两个数进入序列 \(a\),而序列 \(a\) 的中位数只可能是之前中位数的那个位置及其左右位置的数,也就是说中位数的位置只可能保持不动,或者向左移动一位,或者向右移动一位。
所以我们要判断,之前中位数的左边或者右边再添加了两个数之后是不是可以出现当前这个中位数。我们可以用 \(set\) 来维护插入后的数组。
当新的中位数等于之前的中位数的时候,显然是可以的。
当不等的时候,我们判断一下周围两个数能不能是当前这个中位数就可以了。
代码:
#include <bits/stdc++.h>
using namespace std;
int T, n;
void solve(){
scanf("%d", &n);
vector <int> a(n);
for (int i = 0; i < n; ++ i)
scanf("%d", &a[i]);
set<int> s;
s.insert(a[0]);
for (int i = 1; i < n; ++ i){
s.insert(a[i]);
if (a[i] == a[i - 1]) continue;
int x = min(a[i], a[i - 1]), y = max(a[i], a[i - 1]);
if (*s.upper_bound(x) != y){
puts("NO");
return;
}
}
puts("YES");
}
int main(){
cin >> T;
while (T--)
solve();
return 0;
}