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

目录

  • A - Make It Zero
  • B - 2D Traveling
  • C - Fill in the Matrix

A - Make It Zero

原题链接

题目描述
给你一个长度为n( n ≥ 2 n \ge 2 n2)的数组arr,你可以进行最多8次以下的操作,让arr中所有的元素变为0

  • 选择一段区间 [ l , r ] [ l, r] [l,r],让区间中的元素进行异或,假设这段区间的异或和为s
  • 将刚刚选择的区间 [ l , r ] [ l, r] [l,r]中所有的元素替换为s

问需要多少次操作可以让arr中所有的元素变为0,并输出你每次选择的区间 [ l , r ] [l,r] [l,r],如果有多个答案,输出任意一个。

思路:分类讨论+思维+位运算

  • n为偶数,那么直接选择两次区间 [ 1 , n ] [1,n] [1,n]异或,最终arr中所有的元素变为0
  • n为奇数,先选择两次区间 [ 2 , n ] [2,n] [2,n]异或,那么arr [ 2 , n ] [2,n] [2,n]的元素全部变为0,再选择两次区间 [ 1 , 2 ] [1,2] [1,2]异或,最终arr中所有的元素变为0
public static void solve() throws IOException {
    int n = readInt();
    int[] arr = utils.nextIntArray(n);
    if (n % 2 == 0) {
        printWriter.println(2);
        printWriter.println(1 + " " + n);
        printWriter.println(1 + " " + n);
    } else {
        printWriter.println(4);
        printWriter.println(2 + " " + n);
        printWriter.println(2 + " " + n);
        printWriter.println(1 + " " + 2);
        printWriter.println(1 + " " + 2);
    }
}

B - 2D Traveling

原题链接

题目描述
一个二维平面上有n个城市,其中前k个为主要城市。小明想要从一个城市a到城市b去旅游,在这期间他可以去任意的城市,如果经过的两个城市 i , j i,j i,j都是主要城市,那么期间花费为0,如果不是,那么需要消耗 ∣ x i − x j ∣ + ∣ y i − y j ∣ |x_i - x_j| + |y_i - y_j| xixj+yiyj的花费。现在需要你求出最小花费,使得小明可以从ab

思路:分类讨论+数学

  • k = 0 k=0 k=0或者 k = 1 k=1 k=1时,此时不需要经过其他任意城市,直接求ab的距离,因为两点之间,线段最短。
  • k ≥ 2 k \ge 2 k2时,此时需要考虑是否经过主要城市,枚举离a最近的主要城市和离b最近的主要城市,算出经过这两个主要城市的距离与a直接到b的距离取最小值即可。
public static void solve() throws IOException {
    int n = readInt(), k = readInt(), s = readInt(), e = readInt();
    Pair[] pairs = new Pair[n + 1];
    Arrays.setAll(pairs, g -> new Pair());
    for (int i = 1; i <= n; i++) {
        pairs[i] = new Pair(readInt(), readInt());
    }
    long a = pairs[s].first, b = pairs[s].second, c = pairs[e].first, d = pairs[e].second;
    long dis = getDis(a, c) + getDis(b, d);
    if (k == 0 || k == 1) {
        printWriter.println(dis);
    } else {
        long dis2 = Long.MAX_VALUE, dis3 = Long.MAX_VALUE;
        int use = 0;
        // 算出离a最近的城市
        for (int i = 1; i <= k; i++) {
            if (getDis(a, pairs[i].first) + getDis(b, pairs[i].second) < dis2) {
                dis2 = getDis(a, pairs[i].first) + getDis(b, pairs[i].second);
                use = i;// 避免城市重复选
            }
        }
        // 算出离b最近的城市
        for (int i = 1; i <= k; i++) {
            if (i != use && getDis(c, pairs[i].first) + getDis(d, pairs[i].second) < dis3) {
                dis3 = getDis(c, pairs[i].first) + getDis(d, pairs[i].second);
            }
        }
        printWriter.println(Math.min(dis, dis2 + dis3));
    }
}
// 计算两点间的距离
public static long getDis(long a, long b) {
    long res = 0;
    if (a >= 0 && b >= 0) {
        res = Math.abs(a - b);
    } else if (a <= 0 && b <= 0) {
        b = Math.abs(b); a = Math.abs(a);
        res = Math.abs(a - b);
    } else if (a >= 0 && b <= 0) {
        res = Math.abs(b) + a;
    } else if (a <= 0 && b >= 0) {
        res = Math.abs(a) + b;
    }
    return res;
}

C - Fill in the Matrix

原题链接

题目描述
有一个 n × m n × m n×m的二维矩阵M,这个矩阵的每一行必须是一个 0 ∼ m − 1 0 \sim m-1 0m1的排列,现在,我们定义这个矩阵Mi列的美好度 v i v_i vi表示为 m e x ( M 1 , i , M 2 , i , . . . , M n , i ) mex(M_{1,i},M_{2,i},...,M_{n,i}) mex(M1,i,M2,i,...,Mn,i),其中 m e x mex mex函数表示这一列未出现的最小的自然数。最终这个矩阵M的美好度表示为 m e x ( v 1 , v 2 , . . . , v m ) mex(v_1,v_2,...,v_m) mex(v1,v2,...,vm)。现在,给你这个矩阵M的行列分别为n行和m列,请你最大化矩阵M的美好度并求出最终的矩阵。

思路:分类讨论+思维

  • 想要最大化美好度M,当然得尽可能地让 v 1 , v 2 , . . . , v m v_1,v_2,...,v_m v1,v2,...,vm的值可以作为一个 0 ∼ m − 1 0 \sim m-1 0m1的排列,这样,矩阵M的美好度就为 m m m,最大化M美好度的方式就是让排列 1 ∼ m − 1 1 \sim m-1 1m1不断循环移动,但最多移动 m − 1 m-1 m1次。
  • 首先特判 m = 1 m=1 m=1的情况,此时矩阵的值全为0,那么 m e x ( M 1 , 1 , M 2 , 1 , . . . , M n , 1 ) = 1 mex(M_{1,1},M_{2,1},...,M_{n,1})=1 mex(M1,1,M2,1,...,Mn,1)=1,则 m e x ( v 1 ) = 0 mex(v_1)=0 mex(v1)=0
  • 然后讨论n m − 1 m-1 m1的关系
    - n ≥ m − 1 n \ge m-1 nm1,此时可以让排列移动 m − 1 m-1 m1次,美好度最大为 m m m
    - n < m − 1 n \lt m - 1 n<m1,此时排列无法移动 m − 1 m-1 m1次,美好度最大为 n + 1 n+1 n+1
public static void solve() throws IOException {
    int n = readInt(), m = readInt();
    int[] arr = new int[m];
    for (int i = 0; i < m; i++) arr[i] = i;// 排列
    int[][] map = new int[n][m];
    // 特判 m = 1的情况
    if (m == 1) {
        printWriter.println(0);
        for (int i = 0; i < n; i++) {
            printWriter.println(0);
        }
        return;
    }
    int curRow = 0;
    // 判断是否让排列arr移动 m - 1次
    printWriter.println(n >= m - 1 ? m : n + 1);
    for (int i = 1; i < m - 1 && curRow < n; i++, curRow++) {
        for (int j = 0; j < m; j++) {
            printWriter.print(arr[j] + " ");
        }
        printWriter.println();
        arr = nextPermulation(arr, m);
    }
    for (int i = curRow; i < n; i++) {
        for (int j = 0; j < m; j++) {
            printWriter.print(arr[j] + " ");
        }
        printWriter.println();
    }
}
// 构造循环移动后的新排列
public static int[] nextPermulation(int[] arr, int m) {
    int t = arr[0];
    for (int i = 0; i < m - 1; i++) arr[i] = arr[i + 1];
    arr[m - 1] = t;
    return arr;
}

你可能感兴趣的:(数学,分类讨论,算法)