Educational Codeforces Round 112 (Rated for Div. 2)(补题)
Posted 佐鼬Jun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Educational Codeforces Round 112 (Rated for Div. 2)(补题)相关的知识,希望对你有一定的参考价值。
B. Two Tables
题意: 给定一个W*H的矩形,在里面有一个蓝色桌子,坐标(左右顶点)(x1,y1)(x2,y2),然后还要在里面放一个红色桌子,要想放开红色桌子,问你蓝色桌子移动的最小距离。
思路: 只需要单一的上下左右移动即可,因为蓝色方块向单一方向移动,对另一个方向是没有贡献的(也可以理解为,因为蓝色方块周边的区域总是有长或者宽是和W或H是一样的,所以就不用再动它了)
知道只用单一移动的话,就把所有情况讨论出来就行了,上下左右移动的最小值取出来就行
#include <bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
int W, H;
int x1, y1, x2, y2;
int ww, hh;
int main() {
int t;
scanf("%d", &t);
while (t--) {
int ax, ay, bx, by;
int dis = inf;
scanf("%d%d", &W, &H);
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
scanf("%d%d", &ww, &hh);
ax = max(0, ww - x1); //向右移动距离
ay = max(0, hh - y1); //向上移动距离
//再没越界的情况下,取移动最小值
if (ax + x2 <= W) dis = min(dis, ax);
if (ay + y2 <= H) dis = min(dis, ay);
bx = max(0, x2 - (W - ww)); //向左移动
by = max(0, y2 - (H - hh)); //向下移动
//在没越界的情况下取移动最小值
if (x1 - bx >= 0) dis = min(dis, bx);
if (y1 - by >= 0) dis = min(dis, by);
//如果没更新过说明,移动越界了
if (dis == inf)
puts("-1");
else
printf("%.9lf\\n", (double)dis);
}
return 0;
}
C. Coin Rows
题意: 有2*n的矩阵,矩阵里有相应的点数,游戏得分为Bob得分,Alice先走,Alice想让Bob得分最小,Bob想得分最多,双方都进行最优策略,那么游戏结束时,得分为多少(一开始理解错题意了,一维Alice想让自己得分最少,想了半天没想明白)
思路: 对于Bob来说,只有两种方案,要么向右走最后向下走,要么向下走一个然后再一直向右走。
证: 对于Alice来说,Alice可以走的方案,只有下面三种图案
那么对于Bob来说,Alice如果走前两种方案,那么Bob只要走相反图案路线就行,如果是第三种,对于Bob只能吃到左下或者右上的分数,所以只要比较左下或右上哪个分数大,就抄那个路线走。
例如,右上角分数总和大,那就Bob一直向右走在向下走就行。
所以,综上所述,无论是那种情况,Bob都只能走两种方案,就是思路里写的。
此时就提前算出每种情况的左下角的总值和右上角的总值
也就是前缀和和后缀和的
Alice要让Bob分数最小化,也就是说让Bob选择的方案是Bob所有最好方案的最小值(就是只能让Bob选这条路走)
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
#define inf 0x3f3f3f3f
int a[N], b[N];
int sum1[N], sum2[N];
int main() {
int t;
scanf("%d", &t);
while (t--) {
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for (int j = 1; j <= n; j++) {
scanf("%d", &b[j]);
b[j] += b[j - 1];
}
for (int i = n; i >= 1; i--) {
a[i] += a[i + 1];
}
int res = inf;
//枚举Alice从哪个点开始向下走
for (int i = 1; i <= n; i++) {
res = min({res, max(a[i + 1], b[i - 1])});
}
printf("%d\\n", res);
}
return 0;
}
D. Say No to Palindromes
题意: 定义美丽字符串为,其子串没有长度大于等于2的回文子串,只要没有,就是美丽字符串。
题目中字符串只有abc组成
现在m次查询,问你截取
[
l
,
r
]
[l,r]
[l,r]的字符串,问你把他变成美丽字符串的最小操作数,并输出。
思路: 一个字符串的子串想要不回文
拿开头是a举例,第二个只能放‘b’/‘c’,此时放b,那么第三个只能放‘c’,第四个只能放‘a’,…一旦不这样放,就会出现回文。
所以就形成了abcabcabc循环的串
一共有六种循环串
abc,acb,bac,bca,cab,cba
只要那
[
l
,
r
]
[l,r]
[l,r]的串与这六种循环串进行对比,看不同单字符个数,不同的就是要操作的个数,最终取最小值就行。
为降低时间复杂度,可以利用前缀和,提前预处理出来与六种循环串不同字符的个数,最终直接sum[l]-sum[r-1]就行
对于
l
=
r
和
l
+
1
=
r
l=r和l+1=r
l=r和l+1=r特判就行
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
#define inf 0x3f3f3f3f
char s[N];
int n, m;
int sum[N][6];
char p[N][6];
int main() {
scanf("%d%d", &n, &m);
scanf("%s", s + 1);
for (int i = 0; i < 6; i++) {
char x = 'a' + i % 3;
for (int j = 1; j <= n; j++) {
p[j][i] = x;
if (i > 2) {
x++;
if (x == 'd') x = 'a';
} else {
if (x == 'a')
x = 'c';
else
x--;
}
}
for (int j = 1; j <= n; j++) {
sum[j][i] = sum[j - 1][i] + (s[j] != p[j][i]);
}
}
while (m--) {
int l, r;
scanf("%d%d", &l, &r);
if (l == r)
puts("0");
else if (l + 1 == r) {
if (s[l] != s[r])
puts("0");
else
puts("1");
} else {
int res = inf;
for (int i = 0; i < 6; i++) {
res = min(res, sum[r][i] - sum[l - 1][i]);
}
printf("%d\\n", res);
}
}
return 0;
}
To be continued
如果你有任何建议或者批评和补充,请留言指出,不胜感激
以上是关于Educational Codeforces Round 112 (Rated for Div. 2)(补题)的主要内容,如果未能解决你的问题,请参考以下文章
Educational Codeforces Round 7 A
Educational Codeforces Round 7
Educational Codeforces Round 90
Educational Codeforces Round 33