CodeForces Round 885 div2

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);  
        }  
    }  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值