Codeforces Round 885 (Div. 2) A-C java题解

14 篇文章 0 订阅
12 篇文章 0 订阅

A题

维卡和她的朋友们去商场购物,商场可以表示为一个由边长为 n n n m m m 的房间组成的长方形网格。开始的时候维卡位于坐标 ( x x x, y y y), 他有 k k k个朋友,分别位于给定的坐标中(可能重复),每隔一分钟,维卡先移动到她选择的一个相邻房间,然后每个朋友(看到维卡的选择)也选择一个相邻房间移动,上下左右为相邻房间。如果分钟结束时(即所有女孩都移动到相邻房间后),至少有一个朋友与维卡在同一个房间,她就会被抓住。维卡能永远逃离她那些讨厌的朋友吗?能就输出“Yes”,否则输出“No”。

思路

  • 如果存在一个朋友的坐标和(即 x + y x+y x+y)奇偶性与vika相同,则vika一定会被抓到
  • 想象成国际象棋的棋盘,一个格子到另外一个格子的颜色一定不相同
  • 在vika没有到达边界时,追vika的人与vika的距离是固定的(哈曼顿距离),当到达边界时,再移动二者的距离会越来越近,最终一定会被抓到
  • 思路源于灵神

代码

public static void solve() throws IOException {
    int n = readInt(), m = readInt(), k = readInt();
    int x = readInt(), y = readInt();
    boolean flag = false;
    for (int i = 1; i <= k; i++) {
        int a = readInt(), b = readInt();
        if ((x + y) % 2 == (a + b) % 2) {
            flag = true;// 存在奇偶性相同的朋友
        }
    }
    printWriter.println(flag ? "No" : "Yes");
}

B题

河上有一条由 n n n 块带着颜色的木板构成的一座桥,维卡想要通过这座桥,但是他只能踩着相同颜色的木板扩过,否则会破坏桥的外观,现在,维卡站在第一块木板前的地面上。然后,维卡每走 m + 1 m+1 m+1 步,就要跨过 i 1 − 1 , i 2 − i 1 − 1 , i 3 − i 2 − 1 , … , i m − i m − 1 − 1 , n − i m i_1−1,i_2−i_1−1,i_3−i_2−1,…,i_m−i_m−1−1,n−i_m i11,i2i11,i3i21,,imim11,nim块木板。当然维卡现在有一种颜料可以改变其中跨越的木板的颜色,求出所有颜色的木板最大的跨越距离中的最小值。

思路

  • 先记录下每种颜色的木板的坐标
  • 再记录下每种颜色木板要跨越的距离
  • 对每种颜色木板的距离进行排序,再对改颜色跨越最大距离进行减半(因为可以改变中间跨越的一块木板颜色,修改最中间的那块木板收益最大)
  • B题思路来源

代码

public static void solve() throws IOException {
    int n = readInt(), k = readInt();
    //用于记录每种颜色的木板出现的坐标
    List<Integer>[] list = new List[k + 5];
    Arrays.setAll(list, g -> new ArrayList<>());
    for (int i = 1; i <= k; i++) {
        list[i].add(0);//头
    }
    for (int i = 1; i <= n; i++) {
        int a = readInt();
        list[a].add(i);
    }
    for (int i = 1; i <= k; i++) {
        list[i].add(n + 1);//尾
    }
    //用于记录相同颜色木板要跨越的距离
    List<Integer>[] dis = new List[k + 5];
    Arrays.setAll(dis, g -> new ArrayList<>());
    for (int i = 1; i <= k; i++) {
        for (int j = 1; j < list[i].size(); j++) {
            dis[i].add(list[i].get(j) - list[i].get(j - 1) - 1);//按照题目进行模拟
        }
    }
    int res = Integer.MAX_VALUE;
    for (int i = 1; i <= k; i++) {
        Collections.sort(dis[i]);
        int t = dis[i].get(dis[i].size() - 1);
        dis[i].remove((Integer) t);
        dis[i].add(t / 2);// 使用颜料让最大值缩小
        Collections.sort(dis[i]);
        res = Math.min(res, dis[i].get(dis[i].size() - 1));//在所有颜色模板的最大距离中取最小值
    }
    printWriter.println(res);
}

C题

有两个长度为 n n n 的非负整数数组,在一次操作中,维卡根据以下原则构造了一个新数组 c : c i = ∣ a i − b i ∣ c:c_i=|a_i−b_i| c:ci=aibi。然后将数组 c重命名为数组 b,同时将数组 b重命名为数组 a,之后维卡对它们重复上述操作。如果数组 a中的所有元素在经过一定次数的此类操作后都变为零,输出“Yes”,否则输出“No”

思路

  • 先不考虑全局的情况,而是拆分成每一个小对,每一对就是 ( a i , b i ) (a_i, b_i) (ai,bi),每次都考虑每队 a i − b i a_i - b_i aibi的差值为0时首次出现的时间,因为后面再出现0就是周期性(周期为3)出现的,最终只要每一对的差值为0时首次出现的时间相同,那么最终 a数组所有元素就可以变为0
  • 然而想要知道他们差值为0时首次出现的时间,这取决于 a i a_i ai b i b_i bi的奇偶性
    图片源于灵神
    图片源于灵神
    • a i a_i ai b i b_i bi的奇偶性是上面三种情况之一,他们的差值首次为0出现的时间是固定的
    • 如果 a i a_i ai b i b_i bi都为偶数时,分别除以一下他们的最大公约数后等价于回到上面的三种情况之
  • 思路源于灵神
public static void solve() throws IOException {
     int n = readInt();
     int[] a = new int[n + 1], b = new int[n + 1];
     for (int i = 1; i <= n; i++) a[i] = readInt();
     for (int i = 1; i <= n; i++) b[i] = readInt();
     int cur = 0;
     for (int i = 1; i <= n; i++) {
         int t = check(a[i], b[i]);
         if (cur == 0) {
             cur = t;
         } else {
             if (t != cur && t != 0) {
                 printWriter.println("No");
                 return;
             }
         }
     }
     printWriter.println("Yes");
 }
 // 判断ai和bi的奇偶性,间接判断0首次出现的时间
 public static int check(int a, int b) {
     if (a == 0 && b == 0) return 0;//都为 0不用考虑,因为任何时刻差值都为 0
     int gcd = gcd(a, b);
     a /= gcd; b /= gcd;
     if ((a & 1) == 0) return 1;// a为偶数,b为奇数
     if ((b & 1) == 0) return 2;// a为奇数,b为偶数
     return 3;// a为奇数,b为奇数
 }
 // 求出最大公约数
 public static int gcd(int a, int b) {
     return b == 0 ? a : gcd(b, a % b);
 }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值