Codeforces Round 910 (Div. 2)
A. Milica and String
题意:修改长度为n的字符串s,使s中’B’的数量为k个,每次操作可以使一段前缀 替换为同一字符
思路:分情况讨论即可,‘B’的数量为k时无需操作;k为0或n时,一次操作将整个字符串改为’B’或非’B’;
其他情况遍历字符串,每次进行增减操作,直到’B’的数量为k;
若遍历完仍无法通过一次操作达成目的,则通过两次操作先清空B,再把k个前缀变为B。
操作次数只有0,1,2。
AC code:
void solve(){
cin >> n >> k;
string s; cin >> s;
int now = 0;
for(char x : s)
if(x == 'B') now ++;
if(now == k){
cout << 0 << endl;
return;
}
if(k == 0){
cout << 1 << endl;
cout << n << " A" << endl;
return;
}
if(k == n){
cout << 1 << endl;
cout << n << " B" << endl;
return;
}
if(k > now)
for(int i = 0; i < n; i ++){
if(s[i] == 'A') now ++;
if(now == k){
cout << 1 << endl;
cout << i + 1 << " B" << endl;
return;
}
}
if(k < now)
for(int i = 0; i < n; i ++){
if(s[i] == 'B') now --;
if(now == k){
cout << 1 << endl;
cout << i + 1 << " A" << endl;
return;
}
}
cout << 2 << endl;
cout << n << " A" << endl;
cout << k << " B" << endl;
}
B. Milena and Admirer
题意:给出序列a,使序列a变成非递减序列,每次操作可以选择任意一个数组元素 a i a_i ai,然后替换为x和 a i a_i ai - x,然后放入原数组中,即每次操作会使数组个数+1,最少需要多少次操作
思路:当出现非递减元素时,最佳拆分应尽可能平均的将当前数进行拆分成小于后者的数,即拆分成k = (a[i] + a[i + 1] - 1) / (a[i + 1])个数,需要的操作次数为(k - 1)次,此时插入序列中靠后的数为a[i] / k。
AC code:
void solve(){
cin >> n;
int mi = 1e18, u = 0;
for(int i = 1; i <= n; i ++){
cin >> a[i];
}
int ans = 0;
for(int i = n - 1; i >= 1; i --){
if(a[i] > a[i + 1]){
int casual = (a[i] + a[i + 1] - 1) / a[i + 1];
ans += casual - 1;
a[i] /= casual;
}
}
cout << ans << endl;
}
C. Colorful Grid
题意:有一张n行m列的网点图,点与点之间连通,现在需要构造一条连通(1, 1)和(n, m)的路,路上经过点与点之间的道路颜色交叉出现,且经过道路的步数为k,允许多次经过同一点,包括起点和终点。
思路:
- 首先最短路径为mi = (n - 1) + (m - 1),即沿边到达目的地,若k小于mi则不可能构造成功;
- 当(k - mi)为奇数时,需要多次经过同一路径以增加步数,往返一定会是偶数,奇数不可能构造成功;
- 然后处理多出最短路的情况,有两种处理方式
- 一是在终点处绕圈,每轮额外消耗步数为4
- 二是在经过任一段路径时进行绕路,即不直接从一点到另一点,经过另外两点再到该点,这里定为起点,额外消耗步数为2;
- 注意,处理(k - mi)% 4为2是需要处理第二种情况
AC code:
void solve(){
cin >> n >> m >> k;
int mi = (n - 1) + (m - 1);
if(k < mi || (k - mi) % 2){
cout << "NO" << endl;
return;
}
//(n - 1)m
cout << "YES" << endl;
if((k - mi) % 4 == 0){
int flag = 1;
for(int i = 1; i < m; i ++){
if(flag) row[1][i] = 'B';
else row[1][i] = 'R';
flag ^= 1;
}
for(int i = 1; i < n; i ++){
if(flag) col[i][m] = 'B';
else col[i][m] = 'R';
flag ^= 1;
}
}else{
int flag = 0;
for(int i = 1; i < m; i ++){
if(flag) row[1][i] = 'B';
else row[1][i] = 'R';
flag ^= 1;
}
for(int i = 1; i < n; i ++){
if(flag) col[i][m] = 'B';
else col[i][m] = 'R';
flag ^= 1;
}
row[2][1] = 'B';
}
if(col[n - 1][m] == 'B') col[n - 1][m - 1] = 'B', row[n][m - 1] = 'R', row[n - 1][m - 1] = 'R';
else col[n - 1][m - 1] = 'R', row[n][m - 1] = 'B', row[n - 1][m - 1] = 'B';
for(int i = 1; i <= n; i ++){
for(int j = 1; j < m; j ++){
if(row[i][j] == 'B' || row[i][j] == 'R') cout << row[i][j] << " ";
else cout << 'R' << " ";
}cout << endl;
}
for(int i = 1; i < n; i ++){
for(int j = 1; j <= m; j ++){
if(col[i][j] == 'B' || col[i][j] == 'R') cout << col[i][j] << " ";
else cout << 'R' << " ";
}cout << endl;
}
}
D. Absolute Beauty
题意:ab数组的价值为对应位置差的绝对值,现在可以交换一次b数组两数的位置,使价值最大,也可以选择不交换
思路:考虑两种情况,即a >= b和 a <= b当前对应位置的情况,通过交换两种情况中最大的较小值和最小的较大值来达到最优的增加其价值的可能,注意处理交替交换的情况以及无需交换的情况。
AC code:
void solve(){
cin >> n;
vector<int> a(n), b(n);
int maa = 0, mab = 0, mia = 1e18, mib = 1e18;
for(int i = 0; i < n; i ++){
cin >> a[i];
}
int res = 0;
for(int i = 0; i < n; i ++){
cin >> b[i];
//a1 > b1 > a2 > b2
if(a[i] >= b[i]){
maa = max(maa, b[i]);//最大的较小值
mia = min(mia, a[i]);//最小的较大值
}
//b1 > a1 > b2 > a2
if(a[i] <= b[i]){
mab = max(mab, a[i]);
mib = min(mib, b[i]);
}
res += abs(a[i] - b[i]);
}
int ma = 0;
//交换后可能增加的情况
ma = max(ma, max(max(maa - mia, mab - mib), max(mab - mia, maa - mib)));
cout << res + 2 * ma << endl;
}