蓝桥杯 第 3 场算法双周赛(A-D) 解题报告 | 珂学家


前言


整体评价

这场题变多了,但是难度不如上周,G题是道经典的博弈题,H题是一道有趣的图论题,需要优化(过河拆桥)。

这篇主要写A~D的题解,下一篇写E-H的题解。

蓝桥杯 第 3 场算法双周赛


A. 双十一的祈祷

Q: 11^{1111 }的各位数是?

以双十一为主题的签到题,答案自然是1

如果不是11为底,而是其他数字,那可以用快速幂,也可以用找循环节的思路来求解

public class Main {
    public static void main(String[] args) {
        System.out.println(1);
    }
}

ps:

粗略地写下 找循环节的函数,有点像基环树

先找到环的入口,然后把环提取出来

当然这边要分类考虑

  • 一个在环入口之前
  • 一个在环内部循环
    public static int getLoop(int b, int v) {
        // 相当于找到环的入口
        Map<Integer, Integer> hash = new HashMap<>();
        int r = 1;
        int i = 0;
        while (!hash.containsKey(r)) {
            // 在环的入口前遇到,提前推出
            if (v == i) return r;
            hash.put(r, i++);
            r = r * b % 10;
        }

        // 提取环
        List<Integer> arr = new ArrayList<>();
        int s = r;
        do {
            arr.add(s);
            s = s * b % 10;
        } while (s != r);

        int idx = (v - hash.get(r)) % arr.size();
        return arr.get(idx);
    }

B. 疯狂的促销

Q: 比价系统,对于一个商品,淘宝/京东/拼多多都有自己的优惠策略,求购买多个商品的全场最低价(好耳熟的口号)?

按需求描述,模拟即可

import java.io.BufferedInputStream;
import java.util.Scanner;

public class Main {

    static long minPrice(int v) {
        int p1 = v >= 500 ? (v - v / 10) : v;
        int p2 = v >= 1000 ? v - 150 : v;
        int p3 = v == 1111 ? 0 : (v - v / 20);
        return Math.min(p1, Math.min(p2, p3));
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        int n = sc.nextInt();
        long acc = 0;
        for (int i = 0; i < n; i++) {
            int v = sc.nextInt();
            acc += minPrice(v);
        }
        System.out.println(acc);
    }

}

C. 被替换的身份证

Q: 每个选手各2张牌,看谁先出完?

分类讨论即可

  • 先手方是对子,王炸
  • 先手方的有一张单牌最大,且后手方没王炸
import java.io.*;
import java.util.*;

public class Main {

    static boolean isPair(char c1, char c2) {
        return c1 == c2;
    }

    static boolean isBomb(char c1, char c2) {
        if (c1 == 'M' && c2 == 'F') return true;
        if (c1 == 'F' && c2 == 'M') return true;
        return false;
    }

    static int maxCard(char[] str) {
        String p = "3456789XJQKA2MF";
        return Math.max(p.indexOf(str[0]), p.indexOf(str[1]));
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        int t = sc.nextInt();
        while (t -- > 0) {
            char[] card1 = sc.next().toCharArray();
            char[] card2 = sc.next().toCharArray();

            if (isPair(card1[0], card1[1]) || isBomb(card1[0], card1[1])) {
                System.out.println("ShallowDream");
            } else {
                int p1 = maxCard(card1);
                int p2 = maxCard(card2);
                if (p1 >= p2 && !isBomb(card2[0], card2[1])) {
                    System.out.println("ShallowDream");
                } else {
                    System.out.println("Joker");
                }
            }
        }
    }

}

D. 迷宫逃脱

Q: N*M的矩阵中,只能向下向右,且遇到相邻互质,需要消耗钥匙,求在最多消耗Q把钥匙的前提下,路径累计和最大。

这是一道经典的递推DP题

令 dp[i][j][s],  为i,j位置下消耗了s把钥匙的最大路径和

则 dp[i][j][s] = max(dp[i - 1][j][s1],dp[i][j - 1][s2]) + grid[i][j]

这边的s1,s2和 gcd(grid[i - 1][j], grid[i][j]) 有关,如果互质,则s1 = s - 1, 否则 s1 = s, s2亦是如此

这题需要快读板子

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {

    static long gcd(long a, long b) {
        return b == 0 ? a : gcd(b, a % b);
    }

    public static void main(String[] args) {
        AReader sc = new AReader();

        int n = sc.nextInt(), m = sc.nextInt(), k = sc.nextInt();

        long[][] grid = new long[n][m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                grid[i][j] = sc.nextInt();
            }
        }

        long inf = Long.MIN_VALUE / 10;
        long[][][] dp = new long[n][m][k + 1];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                Arrays.fill(dp[i][j], inf);
            }
        }

        // 左上角的位子
        for (int i = 0; i <= k; i++) {
            dp[0][0][i] = grid[0][0];
        }

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                for (int t = 0; t <= k; t++) {
                    if (dp[i][j][t] == inf) continue;
                    if (i + 1 < n) {
                        long x = gcd(grid[i][j], grid[i + 1][j]);
                        if (x > 1) {
                            dp[i+1][j][t] = Math.max(dp[i+1][j][t], dp[i][j][t] + grid[i + 1][j]);
                        } else if (t < k) {
                            dp[i+1][j][t + 1] = Math.max(dp[i+1][j][t + 1], dp[i][j][t] + grid[i + 1][j]);
                        }
                    }

                    if (j + 1 < m) {
                        long x = gcd(grid[i][j], grid[i][j + 1]);
                        if (x > 1) {
                            dp[i][j + 1][t] = Math.max(dp[i][j + 1][t], dp[i][j][t] + grid[i][j + 1]);
                        } else if (t < k) {
                            dp[i][j + 1][t + 1] = Math.max(dp[i][j + 1][t + 1], dp[i][j][t] + grid[i][j + 1]);
                        }
                    }
                }
            }
        }

        long ans = inf;
        for (int i = 0; i <= k; i++) {
            ans = Math.max(ans, dp[n - 1][m - 1][i]);
        }

        System.out.println(ans <= 0 ? -1 : ans);
    }

    static
    class AReader {
        private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        private StringTokenizer tokenizer = new StringTokenizer("");
        private String innerNextLine() {
            try {
                return reader.readLine();
            } catch (IOException ex) {
                return null;
            }
        }
        public boolean hasNext() {
            while (!tokenizer.hasMoreTokens()) {
                String nextLine = innerNextLine();
                if (nextLine == null) {
                    return false;
                }
                tokenizer = new StringTokenizer(nextLine);
            }
            return true;
        }
        public String nextLine() {
            tokenizer = new StringTokenizer("");
            return innerNextLine();
        }
        public String next() {
            hasNext();
            return tokenizer.nextToken();
        }
        public int nextInt() {
            return Integer.parseInt(next());
        }

        public long nextLong() {
            return Long.parseLong(next());
        }

//        public BigInteger nextBigInt() {
//            return new BigInteger(next());
//        }
        // 若需要nextDouble等方法,请自行调用Double.parseDouble包装
    }

}


写在最后

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值