CodeForces Round 885 div2
A题
题意:有一个nxm的网格,女主先动一步,小怪再动一步,如果小怪动完一步之后和女主在同一个网格,则女主game over。
很容易想到曼哈顿距离,因为女主和任意小怪的曼哈顿距离差都是 + 2 + 0 -2,所以只要女主和小怪的曼哈顿距离差为奇数,则小怪永远抓不到女主。
private static void problemA(Scanner sc) {
int t = sc.nextInt();
while(--t >= 0) {
int n = sc.nextInt();
int m = sc.nextInt();
int k = sc.nextInt();
int x = sc.nextInt();
int y = sc.nextInt();
int c = ((x + y) & 1);
String s = "YES";
for (int i = 0; i < k; i++) {
int x1 = sc.nextInt();
int y1 = sc.nextInt();
if (((x1 + y1) & 1) == c) {
s = "NO";
}
}
System.out.println(s);
}
}
B题
题意:简而言之,每种颜色都可组成N条线段,0为起点,n为终点,找出每种颜色的线段的最大值,把它切成两半,然后再找出所有颜色中的最大值的最小值。
private static void problemB(Scanner sc) {
int t = sc.nextInt();
while(--t >= 0) {
int n = sc.nextInt();
int k = sc.nextInt();
int[] a = new int[n];
Map<Integer, List<Integer>> map = new HashMap<>();
for (int i = 0; i < n; i++) {
a[i] = sc.nextInt();
map.computeIfAbsent(a[i], value -> new ArrayList<Integer>(){{add(-1);}}).add(i);
}
int min = Integer.MAX_VALUE;
PriorityQueue<Integer> queue = new PriorityQueue<>(n, (num, other) -> Integer.compare(other, num));
for (int i = 1; i <= k; i++) {
if (!map.containsKey(i)) {
continue;
}
queue.clear();
List<Integer> list = map.get(i);
list.add(n);
for (int j = 1; j < list.size(); j++) {
int len = list.get(j) - list.get(j - 1) - 1;
queue.add(len);
}
Integer first = queue.poll();
Integer second = queue.poll();
assert second != null && first != null;
min = Math.min(min, Math.max(second, first / 2));
}
System.out.println(min);
}
}
C题
题意:给定两个数组,经过操作将数组a的元素全部归零。
由规律可知,数组a变为0之后,继续执行三次又会重新归零,所以只需要计算所有元素归零之后的操作次数 % 3 是否一致即可。
又因为规律可知,当b[i] != 0 && a[i] >= 2 * b[i]时,每三次循环,a[i] -= 2 * b[i],所以可先将a[i] % (2 * b[i])再做模拟。
private static void problemC(Scanner sc) {
int t = sc.nextInt();
while(--t >= 0) {
int len = sc.nextInt();
int[] a = new int[len], b = new int[len];
for (int i = 0; i < len; i++) {
a[i] = sc.nextInt();
}
for (int i = 0; i < len; i++) {
b[i] = sc.nextInt();
}
Set<Integer> set = new HashSet<>();
for (int i = 0; i < len; i++) {
if (a[i] == 0 && b[i] == 0) {
continue;
}
int cnt = 0;
while(a[i] != 0) {
if (b[i] != 0 && a[i] >= 2 * b[i]) {
a[i] %= (2 * b[i]);
continue;
}
int c = Math.abs(a[i] - b[i]);
a[i] = b[i];
b[i] = c;
cnt++;
}
set.add(cnt % 3);
}
String s = set.size() <= 1 ? "YES" : "NO";
System.out.println(s);
}
}
D题
题意:可每天对奖金x投资v,或者取出奖金x,取出奖金x之后,下一天奖金仍然为x不变;v是x的个位数值。
通过规律可知,初始个位数为0, 5会构成0000的循环,所以特殊处理即可。其他个位数最后都会成为一个2 4 8 6的循环。
由贪心思想可知,如果需要投资v,那么一定是第一天开始投资,所以整个操作的最优解一定是先连续投资,再取钱。
对于非0、5的初始个位数而言,我们可以先求出它们投资到个位数2之前的所有值的最大值,然后开始进入循环。
我们可以知道,循环只有4种情况,分别是取到2获得一个最大值、取到4获得最大值、取到8获得一个最大值、取到6获得一个最大值。因此可以暴力求出以上四种情况的最大值的最大值。
当取到6的时候,sum = (s + 20 * n) * (k - 4 * n) -->-80n * n + (20 * k - 4 * s) * n + s * k,其中n为2、4、8、6的循环轮次;这是一个一元二次方程,开口向下,因此可以很直观的得出最大值。
再讨论取到2的时候,实际上就是n轮循环再多加上一个2,因此可以先s+=2,k–;然后再把值重新带入这个一元二次方程。
private static void problemD(Scanner sc) {
class equation {
final long a, b, c;
public equation(long a, long b, long c) {
this.a = a;
this.b = b;
this.c = c;
}
public long getMaxSum() {
// 对称轴
long k = -b / (2 * a);
// k前后两个点也去求
long max = 0;
for (long i = Math.max(0, k - 1); i <= Math.max(0, k + 1); i++) {
max = Math.max(max, a * i * i + b * i + c);
}
return max;
}
}
int t = sc.nextInt();
while(--t >= 0) {
long s = sc.nextInt();
long k = sc.nextInt();
// 贪心思想,如果要获取额外奖金,一定是从最开始获取。
// 除了5、0以外 都是一个循环
// 循环 2 --> 4 --> 8 --> 6 if (s % 10 == 0) {
System.out.println(s * k);
} else if (s % 10 == 5) {
System.out.println(Math.max(s * k, (5 + s) * (k - 1)));
} else {
long ans;
if (k <= 100) {
ans = 0;
while(k > 0) {
ans = Math.max(ans, s * k);
s += (s % 10);
k--;
}
} else {
// 先找到2
ans = s * k;
long p = s % 10;
while(p != 2) {
s += p;
p = (p << 1) % 10;
k--;
ans = Math.max(ans, s * k);
}
// 有四种情况
// sum = (s + 20 * n) * (k - 4 * n) --> -80n * n + (20 * k - 4 * s) * n + s * k
// 再多加一个2
// 再多加一个4
// 再多加一个8
ans = Math.max(ans, new equation(-80, 20 * k - 4 * s, k * s).getMaxSum());
k--; s += 2;
ans = Math.max(ans, new equation(-80, 20 * k - 4 * s, k * s).getMaxSum());
k--; s += 4;
ans = Math.max(ans, new equation(-80, 20 * k - 4 * s, k * s).getMaxSum());
k--; s += 8;
ans = Math.max(ans, new equation(-80, 20 * k - 4 * s, k * s).getMaxSum());
}
System.out.println(ans);
}
}
}