Codeforces Round 903 (Div. 3) 题解 A-E

11 篇文章 0 订阅
5 篇文章 0 订阅

A - Don’t Try to Count

原题链接

题目描述
给你一个长度为n的字符串和S1和一个长度为m的字符串S2,你可以多次对S1进行追加操作,即S1 = S1 + S1,求最少次数让S2作为S1的字串,如果无法满足,输出-1

思路:模拟

  • 使用for循环不好判断终止条件,使用while更好,不容易超时。
public static void solve() throws Exception {
    int n = readInt(), m = readInt();
    String s1 = readString(), s2 = readString();
    int res = 0;
    // res = 0是因为当 s2不是 s1的字串时,可以考虑让 s1至少追加一次,如 s1="abcdef", s2="fa"
    // s1.length() < 2 * m是因为最多只需要让 s1的字符串长度 s1.length() >= 2 * s2.length()
    while (s1.indexOf(s2) == -1 && (res == 0 || s1.length() < 2 * m)) {
        s1 += s1;
        res++;
    }
    if (s1.indexOf(s2) == -1) {
        printWriter.println("-1");
    } else {
        printWriter.println(res);
    }
}

B - Three Threadlets

原题链接

题目描述
给你3根线和一把剪刀,你最多可以使用三次剪刀,使得所有线的长度相等且都是整数,问是否可以满足,如果可以输出YES,否则输出NO

思路:排序+模拟

  • 只需要对长度较长的两根线进行操作,不断进行最多三次操作,看是否可以满足三线长度相等。
public static void solve() throws IOException{
    int[] arr = utils.nextIntArray(3);
    Arrays.sort(arr, 1, 4);
    boolean f = false;
    int i = 1;
    while (i <= 3) {
        if (arr[2] != arr[1]) {// 继续切第二根线或者切了无法满足
            arr[2] -= arr[1];
        } else if (arr[3] != arr[1]) {// 切第三根线或者切了也无法满足
            arr[3] -= arr[1];
        }
        i++;
    }
    if (arr[1] == arr[2] && arr[1] == arr[3]) {// 三线相等
        printWriter.println("YES");
    } else {
        printWriter.println("NO");
    }
}

C - Perfect Square

原题链接

题目描述
给你一个 n ∗ n n * n nn的字符矩阵,你可以对矩阵中的字符进行以下操作:让该字符等于字母表的下一个字符。请你求出最少操作数,使得该矩阵等于该矩阵旋转 90 90 90度后的矩阵。

思路:矩阵模拟

  • 只需要求出对于一个字符,其能旋转到的四个位置上的最大字符即可,例如坐标 [ i , j ] [i,j] [i,j]上的字符可以旋转到的位置有 [ i , j ] , [ j ] [ n − i + 1 ] , [ n − i + 1 ] [ n − j + 1 ] , [ n − j + 1 ] [ i ] [i, j], [j][n - i + 1], [n - i + 1][n - j + 1], [n - j + 1][i] [i,j],[j][ni+1],[ni+1][nj+1],[nj+1][i]。那么只需要求出这四个位置的最大字符即可。
public static void solve() throws IOException {
    int n = readInt();
    char[][] map = utils.nextCharArray(n, n);
    long ops = 0;
    boolean[][] vis =  new boolean[n + 1][n + 1];
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (!vis[i][j]) {// 防止重复遍历
                char ch1 = map[i][j], ch2 = map[j][n - i + 1], ch3 = map[n - i + 1][n - j + 1], ch4 = map[n - j + 1][i];
                int cur = Math.max(ch1, Math.max(ch2, Math.max(ch3, ch4)));
                ops += (cur - ch1) + (cur - ch2) + (cur - ch3) + (cur - ch4);
                vis[i][j] = true;
                vis[j][n - i + 1] = true;
                vis[n - i + 1][n - j + 1] = true;
                vis[n - j + 1][i] = true;
            }
        }
    }
    printWriter.println(ops);
}

D - Divide and Equalize

原题链接

题目描述
给你一个长度为n的数组arr,你可以对他进行以下操作:

  • 选中两个坐标 i , j i,j i,j,然后选择 a i a_i ai的一个约数x,让 a i = a i x , a j = a j ∗ x a_i = \frac{a_i}{x},a_j = a_j * x ai=xaiaj=ajx

问是否可以通过一定的次数,使得arr的所有数相等。

思路:二分答案+大整数

  • 可以先让所有的 a i a_i ai选中的约数为他本身,那么 a j = a j ∗ a i a_j = a_j * a_i aj=ajai,最后会有 n − 1 n - 1 n1个数为1,一个数p为所有数的乘积。
  • 此时只需要判断数p是否可以拆分为&n&个相等数的成绩即可,如: [ 1 , 1 , 1000 ] [1,1,1000] [1,1,1000],最后可以操作为 [ 10 , 10 , 10 ] [10,10,10] [10,10,10]
public static void solve() throws IOException{
    int n = readInt();
    BigInteger sum = BigInteger.ONE;
    for (int i = 1; i <= n; i++) {
        int p = readInt();
        sum = sum.multiply(new BigInteger(p + ""));
    }
    long l = 0, r = (long) 1e6 + 5;
    BigInteger s = sum;
    while (l + 1 < r) {
        long mid = l + r >> 1;
        BigInteger cur = check(mid, n);
        if (cur.compareTo(s) == 0) {
            printWriter.println("YES");
            return;
        } else if (cur.compareTo(s) < 0) {
            l = mid;
        } else {
            r = mid;
        }
    }
    printWriter.println("NO");
}

public static BigInteger check(long x, int n) {
    BigInteger cur = cur = new BigInteger(x + "").pow(n);
    return cur;
}

E - Block Sequence

题目描述
给你一个长度为n的数组arr,它可以拆分为多个块,每个块的第一个元素为块的元素个数,然后该块后面的元素为这个块的所有元素,这样的数组被称为完美序列。你可以删除arr中任意元素,使得arr可以拆分为多个块,求这个最小操作数。

思路:动态规划

  • 从后往前dp,枚举每个位置删与不删,如果对于第i个不满足位置 i + a r r [ i ] + 1 ≤ n + 1 i + arr[i] + 1 \leq n + 1 i+arr[i]+1n+1,那么这个位置只能删,否则,可以取该位置删与不删的最小值。
  • dp数组定义:从 i~n需要达到完美序列的最小操作次数。
public static void solve() throws IOException{
    int n = readInt();
    int[] arr = utils.nextIntArray(n);
    // dp数组定义:从 i~n需要达到完美序列的最小操作次数
    int[] dp = new int[n + 10];
    dp[n + 1] = 0;
    for (int i = n; i >= 1; i--) {
        dp[i] = dp[i + 1] + 1;// 删
        if (i + arr[i] + 1 <= n + 1) {// 不删
            dp[i] = Math.min(dp[i], dp[i + arr[i] + 1]);// 在删与不删中取最大值
        }
    }
    printWriter.println(dp[1]);// 1~n需要达到完美序列的最小操作次数
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值