Codeforces Round 1032 (Div. 3)
卡题卡题疯狂卡题,还刚好卡在中间题了,好好研究一下咋卡题了
A. Letter Home
思路:在一维空间给定一堆散点和当前点位,求经过所有点位所需要的最小步数。首先处理散点的左右边界,所要走的步数就是先走到左右边界的近点,再走一下左右边界的距离即可。9min搞定
/*
Author Owen_Q
*/
#include <bits/stdc++.h>using namespace std;int main() {ios_base::sync_with_stdio(false), cin.tie(nullptr);int t;cin >> t;while (t--) {int n, s;cin >> n >> s;int st = 101, en = 0;for (int i = 0; i < n; i++) {int x;cin >> x;st = min(x, st);en = max(x, en);}int dst = s - st;if (dst < 0) {dst = -dst;}int den = en - s;if (den < 0) {den = -den;}int re = en - st + min(dst, den);cout << re << endl;}return 0;
}
B. Above the Clouds
思路:给定一个小写字母串,要求拆成三个子串,且中间的串要是左右串合并后的子集。这题看起来很麻烦,其实也很简单,因为中间的串完全可以只有一个字母,这题瞬间就降级成,求除两头外,字母串中是否有重复的字母。那么直接用一个数组统计每个字母出现的次数,如果出现某个字母出现两次,则成功。注意特判一下,如果收尾两个字母相同,则该字母必须至少出现3次才算成功。13min搞定
/*
Author Owen_Q
*/
#include <bits/stdc++.h>using namespace std;int main() {ios_base::sync_with_stdio(false), cin.tie(nullptr);int t;cin >> t;while (t--) {int n;cin >> n;string s;cin >> s;int a[26];memset(a, 0, sizeof(a));bool yes = false;for (int i = 0; i < n; i++) {int now = s[i] - 'a';a[now]++;if (i == n - 1 && s[0] == s[n - 1]) {if (a[now] > 2) {yes = true;}} else {if (a[now] > 1) {yes = true;break;}}}if (yes) {cout << "YES" << '\n';} else {cout << "NO" << '\n';}}return 0;
}
C. Those Who Are With Us
思路:卡题的罪魁祸首来了。给定一个矩型数阵,任取一个点,将该点同行同列的数都减一。求减完后矩阵中最大的点最小是多少。
重新抽象一下这题,就是给定多个点,判断这些点是否在十字型区域内。于是开始思维混乱了。首先的思路就是寻找十字型区域的中心,统计x,y坐标,若x坐标重复出现,则x坐标即为十字型区域的x坐标,同理若y坐标重复出现,则y坐标即为十字型区域的y坐标。那么想几种异常case。
首先,case1:重复的x坐标和y坐标不能有多个;Case2:若x坐标出现3个及以上不同时,必须要找到y坐标,同理也是一样。但是很快发现了Case3,这时,用原算法是可以找到第二行第三列为中心位置,但是这时最下方的点其实无法被覆盖,方法破产。于是直接摆烂,在用初始方法找到中心位置后,再把每个点带进去验算。这样居然过了,但总计写了84分钟,逆天啊,再加上没考虑到Case3所带来的10分钟的错误罚时,这题总计消耗了将近一百分钟。
/*
Author Owen_Q
*/
#include <bits/stdc++.h>using namespace std;const int MAXN = 1e5 + 5;int x[MAXN];
int y[MAXN];
int a[MAXN];int main() {ios_base::sync_with_stdio(false), cin.tie(nullptr);int t;cin >> t;while (t--) {int n, m;cin >> n >> m;int maxa = 0;memset(x, 0, sizeof x);memset(y, 0, sizeof y);for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {cin >> a[i * m + j];maxa = max(maxa, a[i * m + j]);}}bool de = true;int xcount = 0;int ycount = 0;int dx = -1;int dy = -1;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (a[i * m + j] == maxa) {x[i]++;y[j]++;if (x[i] == 1) {xcount++;} else {if (dx == -1) {dx = i;} else if (dx != i) {de = false;break;}}if (y[j] == 1) {ycount++;} else {if (dy == -1) {dy = j;} else if (dy != j) {de = false;break;}}if ((ycount > 2 && dx == -1) || (xcount > 2 && dy == -1)) {de = false;break;}}}}for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (a[i * m + j] == maxa) {if (dx != -1 && i != dx && dy != -1 && j != dy) {de = false;break;}}}}if (de) {maxa--;}cout << maxa << endl;}return 0;
}
// 1
// 3 4
// 1 1 100 1
// 1 100 1 1
// 1 1 100 100
这题虽然做出来了,但总感觉不是很踏实,于是去看看大佬都是怎么做的
重新看一下满足规则的Case,可以发现其实任何一个点都满足一个规律,就是其要么在十字型区域的行上,要么在十字型区域的列上。如果某点在十字型区域的行上,那么所有不在这行的点一定在同一列。反之如果某点在十字型区域的列上,那么所有不在这列的点一定在同一行上。基于这个性质,一切都豁然开朗了。先随机找定一个点(假设即为第一个点),然后枚举后面的点,记录下所有行不相同的点,判断列是否相同。再记录下所有列不同的点,判断行是否相同。两者只要有一个满足即可
/*
Author Owen_Q
*/
#include <bits/stdc++.h>using namespace std;const int MAXN = 1e5 + 5;int a[MAXN];int main() {ios_base::sync_with_stdio(false), cin.tie(nullptr);int t;cin >> t;while (t--) {int n, m;cin >> n >> m;int maxa = 0;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {cin >> a[i * m + j];maxa = max(maxa, a[i * m + j]);}}bool dex = true;bool dey = true;int x1 = -1;int x2 = -1;int y1 = -1;int y2 = -1;for (int i = 0; (dex || dey) && i < n; i++) {for (int j = 0; (dex || dey) && j < m; j++) {if (a[i * m + j] == maxa) {if (x1 == -1) {x1 = i;} else if (i != x1) {if (y2 == -1) {y2 = j;} else if (j != y2) {dey = false;}}if (y1 == -1) {y1 = j;} else if (j != y1) {if (x2 == -1) {x2 = i;} else if (i != x2) {dex = false;}}}}}if (dex || dey) {maxa--;}cout << maxa << endl;}return 0;
}
D. 1709
思路:给定两个数串,可以将某个串中的相邻数交换,或者将两个串中相同位置的数交换。要求给定一个方案,使得两个串都由小到大排列且每一位下面的串都对应大于上面的串。
由于这题没要求最优方案,因此给定任意一种方案即可。那么最简单的方式就是先上下交换,确保下面大于上面,再将两个串分别冒泡排序。算一下最坏情况下的步骤数。首先上下交换最坏有 次,即为40次,冒泡排序,最坏交换
次,即为780次,于是最坏的方案次数即为
,完全小于1709,于是,该方案可行。此题耗时28min
/*
Author Owen_Q
*/
#include <bits/stdc++.h>using namespace std;const int MAXN = 41;
const int MAXM = 1709;int a[MAXN];
int b[MAXN];int o[MAXM];
int oi[MAXM];int main() {ios_base::sync_with_stdio(false), cin.tie(nullptr);int t;cin >> t;while (t--) {int n;cin >> n;for (int i = 1; i <= n; i++) {cin >> a[i];}for (int i = 1; i <= n; i++) {cin >> b[i];}int k = 0;for (int i = 1; i <= n; i++) {if (a[i] > b[i]) {o[k] = 3;oi[k] = i;k++;swap(a[i], b[i]);}}for (int i = 0; i < n; i++) {for (int j = 1; j < n - i; j++) {if (a[j] > a[j + 1]) {o[k] = 1;oi[k] = j;k++;swap(a[j], a[j + 1]);}if (b[j] > b[j + 1]) {o[k] = 2;oi[k] = j;k++;swap(b[j], b[j + 1]);}}}cout << k << endl;for (int i = 0; i < k; i++) {cout << o[i] << " " << oi[i] << endl;}}return 0;
}
E. Sponsor of Your Problems
思路:给定两个数,在两个数中间任选一个数,使得该数和两个数相同位的数量最少。其实这题只要想明白的思路也很简单。针对两个数,可以进行按位判断,如果两个数某位相同,则任意一个数一定的该位和两个数一定均相同,即当前位必定带来两个相同位。如果两个数仅相差了1,则至少与其中一个数相同,即必定贡献一个相同位,除此之外,别的情况并不会额外带来相同位数。最后要注意一下,要从高位往低位进行判断,因为如果高位的两个数不相等的话,其实可以往低位进位给足低位足够的空间。当然,如果只近一位都不够。比如0和9,当0进一位后成为10,和9仅相差1,还是可能走到特殊逻辑。而当仅为2或更多时,对于20甚至更大和9作差,则能妥妥保证不会带来新的相同位。27min搞定
/*
Author Owen_Q
*/
#include <bits/stdc++.h>using namespace std;const int MAXN = 10;int al[MAXN];
int ar[MAXN];int main() {ios_base::sync_with_stdio(false), cin.tie(nullptr);int t;cin >> t;while (t--) {int l, r;cin >> l >> r;int n = 0;while (l > 0) {al[n] = l % 10;l /= 10;ar[n] = r % 10;r /= 10;n++;}int re = 0;int addNum = 0;for (int i = n - 1; i >= 0; i--) {if (addNum > 0) {ar[i] += addNum * 10;}if (al[i] == ar[i]) {addNum = 0;re += 2;} else if (al[i] + 1 == ar[i]) {addNum = 1;re++;} else {addNum = 2;}}cout << re << endl;}return 0;
}