Educational Codeforces Round 12
# | 题目 | 分数 | 是否AC |
---|---|---|---|
A | Buses Between Cities | 1600 | ✅ |
B | Shopping | 1400 | ✅ |
C | Simple Strings | 1300 | ✅ |
D | Simple Subset | 1800 | ✅ |
E | Beautiful Subarrays | 2100 | ❌ |
F | Four Divisors | 2400 | ❌ |
A. Buses Between Cities
题目类型 模拟 枚举
题意
给出 A 市到 B 市和 B 市到 A 市公交车、出发的频率以及需要的时间。判断当坐从 A 市到 B 市的某一辆车时,在到达 B 市的图中遇到的公交车的数量。
分析
遇到的公交车共有两种
- 在 m m m 时刻从前出发但未到站
- 在 m m m 时刻之后出发
枚举所有从 B 市出发的车,然后判断是否可以遇到
时间复杂度
O ( ( 1440 − 300 ) / b ) O((1440 - 300) / b) O((1440−300)/b)
代码
public static void solve() throws IOException {
int a = nextInt();
int ta = nextInt();
int b = nextInt();
int tb = nextInt();
char[] s = next().toCharArray();
int m = ((s[0] - '0') * 10 + (s[1] - '0')) * 60 + (s[3] - '0') * 10 + (s[4] - '0');
int cnt = 0;
for (int i = 300; i < 1440; i += b) {
if (i + tb > m && i < m + ta) cnt++;
}
pw.println(cnt);
}
B. Shopping
题目类型 模拟 暴力
题意
k k k 个物品排列一排,然后有 n n n 个顾客每人会购买 m m m 件物品。服务员寻找每个物品的任务量是这个物品所在的索引值(从左往右数第几个)。当一个物品被拿走后,则在最左边新添加一个该物品。现在依次给出每个顾客购买的物品,求最终服务员的任务量是多少。
分析
因为数据范围很小,所以可以模拟购买物品的过程。维护两个数组,一个存储物品排列的状态,另一个维护每个物品对应的索引值。当购买一个物品后需要将这个物品移除并在最左边添加一个该物品,这个操作结束后需要跟新每个物品对应的索引值。
时间复杂度
O ( n 2 ∗ m ) O(n^2 * m) O(n2∗m)
代码
public static void solve() throws IOException {
int n = nextInt();
int m = nextInt();
int k = nextInt();
int[] q = new int[k];
int[] pos = new int[k];
for (int i = 0; i < k; i++) {
q[i] = nextInt() - 1;
pos[q[i]] = i + 1;
}
int cost = 0;
while (n-- > 0) {
for (int i = 0; i < m; i++) {
int x = nextInt() - 1;
cost += pos[x];
remove(q, pos, x);
}
}
pw.println(cost);
}
public static void remove(int[] q, int[] pos, int x) {
for (int i = pos[x] - 1; i > 0; i--) q[i] = q[i - 1];
q[0] = x;
for (int i = 0; i < q.length; i++) pos[q[i]] = i + 1;
}
C. Simple Strings
题目类型 暴力
题意
如果一个字符串 s s s 中所有相邻字符都是不同的,则称这个字符串是一个“简单字符串”。先在给定一个字符串,求将修改尽可能少的字符使这个字符串变为简单字符串,并输出改变后的字符串(如果有多种解,输出任意一个)。
分析
遍历字符串,当发现当前位置的字符与它前一个字符或后一个字符相同时则该字符需要改变,具体变为哪一个可以从 26 26 26 个字母中选一个与其前后都不同的字符即可(这个过程不会执行 26 次,最多只会执行 3 次)。
时间复杂度
O ( 3 ∗ n ) O(3 * n) O(3∗n)
代码
public static void solve() throws IOException {
char[] s = next().toCharArray();
for (int i = 1, len = s.length; i < len; i++) {
if (s[i] == s[i - 1]) {
for (int c = 'a'; c <= 'z'; c++) {
if (s[i - 1] != c
&& ((i + 1 < len && s[i + 1] != c)
|| i + 1 == len)) {
s[i] = (char) c;
break;
}
}
}
}
for (char c : s) pw.print(c);
pw.println();
}
D. Simple Subset
题目类型 数论
题意
如果一个集合中任意两个数的和都是素数,则称这个集合是一个“简单子集”。现在给定一个数组 a a a,求 a a a 的最大简单子集(含有元素最多的简单子集)。
分析
首先考虑两个数和的奇偶情况:
- 奇 数 + 奇 数 = 偶 数 奇数 + 奇数 = 偶数 奇数+奇数=偶数
- 偶 数 + 偶 数 = 偶 数 偶数 + 偶数 = 偶数 偶数+偶数=偶数
- 奇 数 + 偶 数 = 奇 数 奇数 + 偶数 = 奇数 奇数+偶数=奇数
在质数中,除 2 2 2 以外所有的质数都是奇数,所以一个子集中最多包含两个数,因为不论再向集合中添加一个奇数或偶数都会使其和出现非质数。但是对于 1 1 1 要特殊考虑,因为 1 + 1 = 2 1 + 1 = 2 1+1=2, 而 2 2 2 是一个素数。所以当数组中含有 1 1 1 时就会出现两种情况:
- 数组中存在一个数 x x x, 且 x + 1 x + 1 x+1 是一个质数,此时最大简单子集就是 { 1 , 1 , … … , 1 , x } \lbrace 1, 1, ……,1, x \rbrace {1,1,……,1,x}
- 数组中不存在一个数 x x x, 且 x + 1 x + 1 x+1 是一个质数,此时最大简单子集就是 { 1 , 1 , … … , 1 } \lbrace 1, 1, ……,1 \rbrace {1,1,……,1}
可以通过埃氏筛预处理出所有的素数从而加速判断两个数的和是否是质数。
时间复杂度
O ( n + n log log n ) O(n + n\log ^{\log n}) O(n+nloglogn)
代码
static boolean[] prime = new boolean[2000010];
public static void solve() throws IOException {
SOE();
int k = nextInt();
int[] a = new int[k];
int cnt = 0;
for (int i = 0; i < k; i++) {
a[i] = nextInt();
if (a[i] == 1) cnt++;
}
if (cnt >= 2) {
for (int i = 0; i < k; i++) {
if (!prime[a[i] + 1] && a[i] != 1) {
pw.println(cnt + 1);
pw.print(a[i] + " ");
while (cnt-- > 0) pw.print(1 + " ");
pw.println();
return;
}
}
pw.println(cnt);
while (cnt-- > 0) pw.print(1 + " ");
pw.println();
return;
}
for (int i = 0; i < k; i++) {
for (int j = i + 1; j < k; j++) {
if (!prime[a[i] + a[j]]) {
pw.println(2);
pw.println(a[i] + " " + a[j]);
return;
}
}
}
pw.println(1);
pw.println(a[0]);
}
public static void SOE() {
int m = (int) (Math.sqrt(2000010) + 0.5);
for (int i = 2; i <= m; i++)
if (!prime[i])
for (int j = i * i; j < 2000010; j += i) prime[j] = true;
}