java 洛谷题单【算法1-1】模拟与高精度

P1042 [NOIP2003 普及组] 乒乓球

解题步骤(看注释)

  • 读取输入

    • 使用 Scanner 读取所有输入,直到遇到字符 E
    • 将输入中的所有字符(除去 E)拼接成一个字符串。
  • 处理比赛结果

    • 分别按照11分制和21分制处理输入字符串,计算每局的结果。
    • 将每局的结果存储在 List 中,以便后续输出。
  • 输出结果

    • 按顺序输出11分制和21分制的比赛结果。
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder inputBuilder = new StringBuilder();

        // 读取输入,直到输入包含“E”
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine();
            if (line.contains("E")) {
                // 截取输入中“E”之前的字符串
                inputBuilder.append(line, 0, line.indexOf('E'));
                break;
            }
            inputBuilder.append(line);
        }

        String input = inputBuilder.toString();
        // 处理游戏,游戏分数为11
        List<String> results11 = processGames(input, 11);
        // 处理游戏,游戏分数为21
        List<String> results21 = processGames(input, 21);

        // 输出结果,游戏分数为11
        for (String result : results11) {
            System.out.println(result);
        }
        System.out.println();
        // 输出结果,游戏分数为21
        for (String result : results21) {
            System.out.println(result);
        }

        scanner.close();
    }

    private static List<String> processGames(String input, int gamePoint) {
        List<String> results = new ArrayList<>();
        int playerA = 0, playerB = 0;

        // 遍历输入中的每个字符
        for (char point : input.toCharArray()) {
            if (point == 'W') {
                // A得分
                playerA++;
            } else if (point == 'L') {
                // B得分
                playerB++;
            }

            // 当A或B的分数大于或等于gamePoint,且两者的分数差大于等于2时,记录结果
            if ((playerA >= gamePoint || playerB >= gamePoint) && Math.abs(playerA - playerB) >= 2) {
                results.add(playerA + ":" + playerB);
                playerA = 0;
                playerB = 0;
            }
        }

        // 记录最终结果
        results.add(playerA + ":" + playerB);
        return results;
    }
}

P2670 [NOIP2015 普及组] 扫雷游戏

解题步骤

  • 读取输入:首先,我们需要读取网格的尺寸( nm ),然后读取网格本身,其中包含用于地雷的字符 '*''?' 。

  • 初始化结果网格:创建一个网格来存储结果,该结果将是输入网格的副本。这最终将包含代表每个非地雷单元的相邻地雷计数的数字。

  • 定义方向:定义要检查每个单元格周围的八个可能的方向(上、下、左、右和四个对角线)。

  • 遍历网格:对于网格中的每个单元格:

    • 如果它是一个地雷( '*' ),我们不需要为该单元格做任何事情。
    • 如果不是地雷 ( '?' ),请计算相邻单元格中的地雷数量。
  • 输出结果网格:以与输入相同的格式打印结果网格。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取输入的n和m
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        scanner.nextLine();  

        // 初始化grid数组
        char[][] grid = new char[n][m];
        for (int i = 0; i < n; i++) {
            grid[i] = scanner.nextLine().toCharArray();
        }

        // 初始化dx和dy数组
        int[] dx = {-1, -1, -1, 0, 0, 1, 1, 1};
        int[] dy = {-1, 0, 1, -1, 1, -1, 0, 1};

        // 初始化resultGrid数组
        char[][] resultGrid = new char[n][m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == '*') {
                    resultGrid[i][j] = '*';
                } else {
                    // 计算grid[i][j]周围的雷的数量
                    int mineCount = 0;
                    for (int d = 0; d < 8; d++) {
                        int ni = i + dx[d];
                        int nj = j + dy[d];
                        if (ni >= 0 && ni < n && nj >= 0 && nj < m && grid[ni][nj] == '*') {
                            mineCount++;
                        }
                    }
                    resultGrid[i][j] = (char) (mineCount + '0');
                }
            }
        }
        
        // 输出结果
        for (int i = 0; i < n; i++) {
            System.out.println(resultGrid[i]);
        }

        scanner.close();
    }
}

P1563 [NOIP2016 提高组] 玩具谜题

解题步骤

  • 读取输入:读取节点数 n 和指令数 m,然后读取每个节点的信息。
  • 初始化节点数组:创建一个数组存储每个节点的信息。
  • 处理指令:根据每条指令更新当前节点的位置。
  • 输出结果:输出最终的当前节点的名称。
import java.util.Scanner;

class Node {
    int head;
    String name;

    Node(int head, String name) {
        this.head = head;
        this.name = name;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取n和m
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        scanner.nextLine(); // 消耗换行符

        // 初始化数组
        Node[] a = new Node[n];

        // 读取每个节点的信息
        for (int i = 0; i < n; i++) {
            int head = scanner.nextInt();
            String name = scanner.next();
            a[i] = new Node(head, name);
        }

        int now = 0;

        // 处理每个操作
        for (int i = 1; i <= m; i++) {
            int x = scanner.nextInt();
            int y = scanner.nextInt();

            if (a[now].head == 0 && x == 0) {
                now = (now + n - y) % n;
            } else if (a[now].head == 0 && x == 1) {
                now = (now + y) % n;
            } else if (a[now].head == 1 && x == 0) {
                now = (now + y) % n;
            } else if (a[now].head == 1 && x == 1) {
                now = (now + n - y) % n;
            }
        }

        // 输出结果
        System.out.println(a[now].name);

        scanner.close();
    }
}

P1601 A+B Problem(高精)

import java.math.BigInteger;
import java.util.Scanner;

/**
 * @Author HeShen.
 * @Date 2024/3/16 21:03
 */


public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        BigInteger a = new BigInteger(input.next());
        BigInteger b = new BigInteger(input.next());
        System.out.println(b.add(a));

    }
}

P1303 A*B Problem


import java.math.BigInteger;
import java.util.Scanner;

/**
 * @Author HeShen.
 * @Date 2024/3/16 21:03
 */


public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        BigInteger a = new BigInteger(input.next());
        BigInteger b = new BigInteger(input.next());
        System.out.println(b.multiply(a));

    }
}

P1009 [NOIP1998 普及组] 阶乘之和

import java.util.*;
import java.math.*;

public class Main {
    static BigInteger jc(int n) {
        BigInteger i=new BigInteger("1");
        for (int j=2;j<=n;j++) i=i.multiply(new BigInteger(Integer.toString(j)));
        return i;
    }
    public static void main(String[] args) {
        Scanner scan=new Scanner(System.in);
        int n=scan.nextInt();
        scan.close();
        BigInteger sum=new BigInteger("0");
        for (int i=1;i<=n;i++) sum=sum.add(jc(i));
        scan.close();
        System.out.println(sum);
    }
}

// import java.util.Scanner;

// public class Main {
//     public static void main(String[] args) {
//         Scanner input = new Scanner(System.in);
//         int n = input.nextInt();
//         long N = 1;long sum = 0;
//         for (int i = 1; i <= n; i++) {
//             N *= i;
//             sum += N;
//         }
//         System.out.println(sum);
//     }
// }

P4924 [1007] 魔法少女小Scarlet

解题步骤

  • 初始化矩阵:

    • 按行优先顺序使用从 1 到 n^2的值填充矩阵。
  • 定义旋转函数:

    • 对于给定的中心 (x, y) 和半径 r ,提取子矩阵。
    • 通过重新排列元素来顺时针或逆时针旋转子矩阵。
    • 将旋转后的子矩阵复制回原始矩阵。
  • 处理每个旋转命令:

    • 根据中心和半径提取每个命令的子矩阵。
    • 应用命令指定的旋转。
    • 将旋转后的子矩阵放回主矩阵中。
  • 逐行打印矩阵。

 按照上述所说解题可能会存在超时现象(洛谷最后一个用例)。可以改进一下:

优化策略

  1. 减少数据复制: 避免提取和重建子矩阵,直接在原矩阵上操作。
  2. 旋转逻辑优化: 使用更高效的算法来进行矩阵的旋转操作。

具体优化步骤如下:

  1. 直接在原矩阵上进行旋转:

    • 通过旋转算法,将以中心 (x, y) 为中心的子矩阵进行旋转。
    • 使用一个临时数组 temp 存储旋转后的结果,然后再将其写回原矩阵。
  2. 高效旋转逻辑:

    • 通过一次遍历直接进行旋转,减少了重复的操作。
    • 针对顺时针和逆时针两种旋转,分别处理。
import java.util.Scanner;

public class MagicGirlScarlet {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        int n = scanner.nextInt();
        int m = scanner.nextInt();
        int[][] matrix = new int[n][n];
        
        int value = 1;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                matrix[i][j] = value++;
            }
        }
        
        for (int k = 0; k < m; k++) {
            int x = scanner.nextInt() - 1;
            int y = scanner.nextInt() - 1;
            int r = scanner.nextInt();
            int z = scanner.nextInt();
            
            rotate(matrix, x, y, r, z);
        }
        
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (j > 0) System.out.print(" ");
                System.out.print(matrix[i][j]);
            }
            System.out.println();
        }

        scanner.close();
    }

    private static void rotate(int[][] matrix, int x, int y, int r, int z) {
        int size = 2 * r + 1;

        int[][] temp = new int[size][size];

        // 将原始矩阵中需要旋转的部分复制到临时矩阵中
        for (int i = 0; i < size; i++) {
            System.arraycopy(matrix[x - r + i], y - r, temp[i], 0, size);
        }

        // 根据旋转方向,将临时矩阵中的元素复制回原始矩阵
        if (z == 0) { 
            for (int i = 0; i < size; i++) {
                for (int j = 0; j < size; j++) {
                    matrix[x - r + j][y - r + size - 1 - i] = temp[i][j];
                }
            }
        } else {
            for (int i = 0; i < size; i++) {
                for (int j = 0; j < size; j++) {
                    matrix[x - r + size - 1 - j][y - r + i] = temp[i][j];
                }
            }
        }
    }
}

P1328 [NOIP2014 提高组] 生活大爆炸版石头剪刀布

解题步骤

  • 初始化和输入读取

    • 读取比赛轮数 n,选手 A 的手势序列长度 na 和选手 B 的手势序列长度 nb
    • 读取选手 A 和选手 B 的手势序列。
  • 定义得分表

    • 根据游戏规则,定义一个二维数组 vs 来表示不同手势之间的胜负关系。
  • 进行比赛并计算得分

    • 使用循环处理每一轮比赛,根据选手的手势序列和当前轮次,计算每个选手的得分。
  • 输出结果

    • 打印两个选手的最终得分。
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取 n, na, nb
        int n = scanner.nextInt();
        int na = scanner.nextInt();
        int nb = scanner.nextInt();
        
        int[] a = new int[na];
        int[] b = new int[nb];
        
        // 读取序列 a
        for (int i = 0; i < na; i++) {
            a[i] = scanner.nextInt();
        }
        
        // 读取序列 b
        for (int i = 0; i < nb; i++) {
            b[i] = scanner.nextInt();
        }
        
        // 得分表
        int[][] vs = {
            {0, 0, 1, 1, 0},
            {1, 0, 0, 1, 0},
            {0, 1, 0, 0, 1},
            {0, 0, 1, 0, 1},
            {1, 1, 0, 0, 0}
        };
        
        int cnta = 0, cntb = 0;
        
        // 进行 n 轮比赛
        for (int i = 0; i < n; i++) {
            cnta += vs[a[i % na]][b[i % nb]];
            cntb += vs[b[i % nb]][a[i % na]];
        }
        
        // 输出结果
        System.out.println(cnta + " " + cntb);
        
        scanner.close();
    }
}

P1518 [USACO2.4] 两只塔姆沃斯牛 The Tamworth Two

解题步骤

要解决这个问题,我们需要模拟 Farmer John 和两只牛在 10x10 网格上的移动。每个角色(Farmer John 和牛)有固定的移动规则:

  1. 如果前方无障碍(包括地图边界),它们会向前移动。
  2. 如果前方有障碍,它们会顺时针转 90 度。

我们需要使用广度优先搜索(BFS)来模拟它们的移动,并检查它们是否在某一步相遇。

关键点

  1. 移动和旋转规则
    • 移动规则:检查前方是否有障碍,如果没有就前进,否则顺时针转向。
  2. 状态表示
    • 每个角色的状态可以用其位置和方向来表示。
    • 两个角色的状态组合起来表示整个系统的状态。
  3. 广度优先搜索(BFS)
    • 使用 BFS 来模拟每分钟的移动,直到两个角色相遇或达到最大步数。

实现步骤

  1. 读取并解析输入地图。
  2. 初始化 Farmer John 和牛的初始状态(位置和方向)。
  3. 使用 BFS 来模拟移动:
    • 在每一步中,根据当前状态计算下一步可能的状态。
    • 如果两个角色在某步末相遇,则返回当前步数。
    • 如果所有可能状态都遍历完仍未相遇,则返回 0。
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {
    //EMPTY未使用,可以删
    private static final int N = 10;
    private static final char OBSTACLE = '*';
    private static final char EMPTY = '.';
    private static final char COWS = 'C';
    private static final char FARMER = 'F';

    private static final int[] dx = {-1, 0, 1, 0}; // 北, 东, 南, 西
    private static final int[] dy = {0, 1, 0, -1};

    private static class State {
        int fx, fy, fd, cx, cy, cd;
        int steps;

        State(int fx, int fy, int fd, int cx, int cy, int cd, int steps) {
            this.fx = fx;
            this.fy = fy;
            this.fd = fd;
            this.cx = cx;
            this.cy = cy;
            this.cd = cd;
            this.steps = steps;
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        char[][] map = new char[N][N];
        int fx = 0, fy = 0, cx = 0, cy = 0;

        // 读取地图并找到 Farmer John 和牛的位置
        for (int i = 0; i < N; i++) {
            map[i] = scanner.next().toCharArray();
            for (int j = 0; j < N; j++) {
                if (map[i][j] == FARMER) {
                    fx = i;
                    fy = j;
                } else if (map[i][j] == COWS) {
                    cx = i;
                    cy = j;
                }
            }
        }

        // 使用 BFS 进行模拟
        boolean[][][][][][] visited = new boolean[N][N][4][N][N][4];
        Queue<State> queue = new LinkedList<>();
        queue.add(new State(fx, fy, 0, cx, cy, 0, 0)); // 初始方向均为北(0)
        visited[fx][fy][0][cx][cy][0] = true;

        while (!queue.isEmpty()) {
            State current = queue.poll();
            if (current.fx == current.cx && current.fy == current.cy) {
                System.out.println(current.steps);
                return;
            }

            // 计算 Farmer John 的下一个状态
            int nfx = current.fx + dx[current.fd];
            int nfy = current.fy + dy[current.fd];
            int nfd = current.fd;
            if (nfx < 0 || nfx >= N || nfy < 0 || nfy >= N || map[nfx][nfy] == OBSTACLE) {
                nfd = (current.fd + 1) % 4; // 顺时针转 90 度
                nfx = current.fx;
                nfy = current.fy;
            }

            // 计算牛的下一个状态
            int ncx = current.cx + dx[current.cd];
            int ncy = current.cy + dy[current.cd];
            int ncd = current.cd;
            if (ncx < 0 || ncx >= N || ncy < 0 || ncy >= N || map[ncx][ncy] == OBSTACLE) {
                ncd = (current.cd + 1) % 4; // 顺时针转 90 度
                ncx = current.cx;
                ncy = current.cy;
            }

            if (!visited[nfx][nfy][nfd][ncx][ncy][ncd]) {
                visited[nfx][nfy][nfd][ncx][ncy][ncd] = true;
                queue.add(new State(nfx, nfy, nfd, ncx, ncy, ncd, current.steps + 1));
            }
        }

        System.out.println(0); // 如果没有相遇,则输出 0
        scanner.close();
    }
}

P1067 [NOIP2009 普及组] 多项式输出

解题步骤

  • 读取输入数据:读取多项式的次数 n 和每项的系数。
  • 处理每个系数:根据系数的值和项的次数构建多项式字符串,注意处理系数为 0 的情况。
  • 格式化输出
    • 最高次项的系数如果是正数,前面不需要加 + 号,如果是负数,则以 - 号开头。
    • 非最高次项根据其系数是正数还是负数,加 +- 号。
    • 系数的绝对值为 1 且指数不为 0 的项,不需要显示系数的 1
    • 处理指数的显示形式(x^bx,或省略 x)。
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取多项式次数
        int n = scanner.nextInt();

        // 读取各项系数
        int[] coefficients = new int[n + 1];
        for (int i = 0; i <= n; i++) {
            coefficients[i] = scanner.nextInt();
        }

        StringBuilder polynomial = new StringBuilder();
        boolean firstTerm = true;

        for (int i = 0; i <= n; i++) {
            int coefficient = coefficients[i];
            int degree = n - i;

            if (coefficient == 0) {
                continue; // 跳过系数为0的项
            }

            // 处理符号
            if (firstTerm) {
                if (coefficient < 0) {
                    polynomial.append("-");
                }
                firstTerm = false;
            } else {
                if (coefficient > 0) {
                    polynomial.append("+");
                } else {
                    polynomial.append("-");
                }
            }

            // 处理系数绝对值
            if (Math.abs(coefficient) != 1 || degree == 0) {
                polynomial.append(Math.abs(coefficient));
            }

            // 处理指数部分
            if (degree > 1) {
                polynomial.append("x^").append(degree);
            } else if (degree == 1) {
                polynomial.append("x");
            }
        }

        System.out.println(polynomial.toString());

        scanner.close();
    }
}

P1098 [NOIP2007 提高组] 字符串的展开

解题步骤

  • 读取输入和解析参数

    • 读取三个参数 p1, p2, p3
    • 读取需要处理的字符串。
  • 处理每一个可能的展开情况

    • 遇到 -,检查其两侧字符是否满足展开条件(同为小写字母或数字且右侧字符大于左侧字符)。
    • 如果满足条件,根据 p1, p2, p3进行相应的展开和格式化。
  • 构建结果字符串

    • 使用 StringBuilder 来高效地构建字符串。
    • 处理每个字符,如果遇到可展开的模式,根据规则生成展开部分并添加到结果中。
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取参数
        int p1 = scanner.nextInt();
        int p2 = scanner.nextInt();
        int p3 = scanner.nextInt();
        scanner.nextLine(); // 吃掉换行符
        String input = scanner.nextLine();
        
        StringBuilder result = new StringBuilder();
        
        int i = 0;
        while (i < input.length()) {
            char current = input.charAt(i);
            
            if (current == '-' && i > 0 && i < input.length() - 1) {
                char left = input.charAt(i - 1);
                char right = input.charAt(i + 1);
                
                // 检查是否可以展开
                if ((Character.isLowerCase(left) && Character.isLowerCase(right) && left < right) ||
                    (Character.isDigit(left) && Character.isDigit(right) && left < right)) {
                    
                    // 不直接处理当前的 '-',而是进入展开逻辑
                    char start = (char) (left + 1);
                    char end = right;
                    
                    StringBuilder expanded = new StringBuilder();
                    for (char ch = start; ch < end; ch++) {
                        char toAppend = ch;
                        if (p1 == 2 && Character.isLowerCase(ch)) {
                            toAppend = Character.toUpperCase(ch);
                        } else if (p1 == 3) {
                            toAppend = '*';
                        }
                        for (int j = 0; j < p2; j++) {
                            expanded.append(toAppend);
                        }
                    }
                    
                    if (p3 == 2) { // 如果需要逆序
                        expanded.reverse();
                    }
                    
                    result.append(expanded);
                } else {
                    // 不能展开,直接添加
                    result.append(current);
                }
            } else {
                // 非 '-' 或者不能展开,直接添加
                result.append(current);
            }
            i++;
        }
        
        System.out.println(result.toString());
        scanner.close();
    }
}

 P1065 [NOIP2006 提高组] 作业调度方案

解题步骤

  • 初始化和输入读取

    • 读取机器数量 m 和工件数量 n
    • 读取工件加工顺序。
    • 读取每个工件的每道工序所使用的机器编号。
    • 读取每道工序的加工时间。
  • 模拟加工过程

    • 使用数组记录每台机器的使用情况。
    • 对于每道工序,找到机器的空闲时间段并记录加工时间。
    • 更新工件的加工完成时间和整体加工时间。
  • 输出结果

    • 输出所有工件完成加工所需的总时间。
import java.util.Scanner;

class Information {
    int id;  // 在第 id 台机器上加工
    int cost;  // 花费 cost 时间

    Information(int id, int cost) {
        this.id = id;
        this.cost = cost;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取 m 和 n
        int m = scanner.nextInt();
        int n = scanner.nextInt();

        // 工件加工顺序列表
        int[] list = new int[m * n + 1];

        // 读取工件加工顺序
        for (int i = 1; i <= m * n; i++) {
            list[i] = scanner.nextInt();
        }

        // 初始化工件加工信息数组
        Information[][] a = new Information[n + 1][m + 1];

        // 读取每个工件的每道工序所使用的机器号
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                int id = scanner.nextInt();
                a[i][j] = new Information(id, 0);  // 先设置 id,稍后再设置 cost
            }
        }

        // 读取每个工件的每道工序的加工时间
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                int cost = scanner.nextInt();
                a[i][j].cost = cost;  // 设置 cost
            }
        }

        // 机器使用情况
        int[][] mac = new int[21][100001];  // 初始化时,数组元素默认为 0

        // 每个工件加工到第几步
        int[] step = new int[21];

        // 每个工件上次加工完的时间
        int[] las_time = new int[21];

        int ans = 0;

        // 处理每个操作
        for (int i = 1; i <= m * n; i++) {
            int now = list[i];
            step[now]++;
            int id = a[now][step[now]].id;
            int cost = a[now][step[now]].cost;

            int s = 0;
            for (int j = las_time[now] + 1;; j++) {
                if (mac[id][j] == 0) {
                    s++;
                } else {
                    s = 0;
                }
                if (s == cost) {
                    for (int k = j - cost + 1; k <= j; k++) {
                        mac[id][k] = 1;
                    }
                    if (j > ans) ans = j;
                    las_time[now] = j;
                    break;
                }
            }
        }

        // 输出结果
        System.out.println(ans);
        
        scanner.close();
    }
}

P1786 帮贡排序

解题步骤

  • 读取输入:读取所有帮派成员的信息,包括他们的名字、职位、帮贡和等级。
  • 初始化职位优先级映射:定义职位的优先级,以便后续排序时使用。
  • 分类和排序:按照帮贡对成员进行第一次排序,忽略帮主和副帮主的位置。
  • 分配新职位:根据排序后的结果重新分配职位。
  • 最终排序和输出:根据新职位和等级对所有成员进行最终排序,并输出结果。
import java.util.*;

class Member {
    String name; // 名字
    String originalPosition; // 原职位
    String newPosition; // 新职位
    long contribution; // 帮贡
    int level; // 等级
    int index; // 输入顺序索引

    Member(String name, String originalPosition, long contribution, int level, int index) {
        this.name = name;
        this.originalPosition = originalPosition;
        this.contribution = contribution;
        this.level = level;
        this.index = index;
    }
}

public class Main {
    // 映射职位到优先级
    static Map<String, Integer> positionMap = new HashMap<>();
    
    static {
        positionMap.put("BangZhu", 0);
        positionMap.put("FuBangZhu", 1);
        positionMap.put("HuFa", 2);
        positionMap.put("ZhangLao", 3);
        positionMap.put("TangZhu", 4);
        positionMap.put("JingYing", 5);
        positionMap.put("BangZhong", 6);
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(); // 读取帮友人数
        scanner.nextLine(); // 消耗换行符

        List<Member> members = new ArrayList<>();
        
        for (int i = 1; i <= n; i++) {
            String name = scanner.next(); // 读取名字
            String originalPosition = scanner.next(); // 读取原职位
            long contribution = scanner.nextLong(); // 读取帮贡
            int level = scanner.nextInt(); // 读取等级
            scanner.nextLine(); // 消耗换行符
            members.add(new Member(name, originalPosition, contribution, level, i)); // 创建成员对象并添加到列表中
        }
        scanner.close();

        // 按帮贡和输入顺序排序(忽略前三个帮主和副帮主)
        Collections.sort(members.subList(3, n), new Comparator<Member>() {
            public int compare(Member x, Member y) {
                if (x.contribution == y.contribution) {
                    return Integer.compare(x.index, y.index);
                } else {
                    return Long.compare(y.contribution, x.contribution);
                }
            }
        });

        // 根据排序后的结果分配新职位
        for (int i = 0; i < n; i++) {
            if (i == 0) {
                members.get(i).newPosition = "BangZhu"; // 帮主
            } else if (i == 1 || i == 2) {
                members.get(i).newPosition = "FuBangZhu"; // 副帮主
            } else if (i == 3 || i == 4) {
                members.get(i).newPosition = "HuFa"; // 护法
            } else if (i >= 5 && i <= 8) {
                members.get(i).newPosition = "ZhangLao"; // 长老
            } else if (i >= 9 && i <= 15) {
                members.get(i).newPosition = "TangZhu"; // 堂主
            } else if (i >= 16 && i <= 40) {
                members.get(i).newPosition = "JingYing"; // 精英
            } else {
                members.get(i).newPosition = "BangZhong"; // 帮众
            }
        }

        // 按新职位、等级和输入顺序排序
        Collections.sort(members, new Comparator<Member>() {
            public int compare(Member x, Member y) {
                if (positionMap.get(x.newPosition).equals(positionMap.get(y.newPosition))) {
                    if (x.level == y.level) {
                        return Integer.compare(x.index, y.index);
                    }
                    return Integer.compare(y.level, x.level);
                }
                return Integer.compare(positionMap.get(x.newPosition), positionMap.get(y.newPosition));
            }
        });

        // 输出结果
        for (Member member : members) {
            System.out.println(member.name + " " + member.newPosition + " " + member.level);
        }
    }
}

P1591 阶乘数码


import java.math.BigInteger;
import java.util.Scanner;

/**
 * @Author HeShen.
 * @Date 2024/3/16 21:03
 */
//首先求出阶乘,然后int转String查找数码出现次数即可
public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int t = input.nextInt();int[] p = new int[t];char[] q = new char[t];
        for (int i = 0; i < t; i++) {
            p[i] = input.nextInt();
            q[i] = input.next().charAt(0);
        }
        for (int i = 0; i < t; i++) {
            String temp = String.valueOf(func(p[i]));
            System.out.println(find(temp, q[i]));
        }

    }

    public static int find(String s, char a){
        int count = 0;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == a) {
                count++;
            }
        }
        return count;
    }

    public static BigInteger func(int num){
        BigInteger n = BigInteger.valueOf(num);
        if (num == 1) return BigInteger.valueOf(num);
        return n.multiply(func(num - 1));
    }

}


P1249 最大乘积

解题步骤

  • 数组初始化

    • int[] a:用于存储分解的自然数。
    • int[] s:用于存储高精度计算结果。
    • int len:记录当前高精度数的长度。
  • 特殊情况处理

    • n == 3n == 4 时,直接输出分解方案和乘积。
  • 贪心分解

    • 从 2 开始逐步增加,将其加入分解方案,直到剩余的数不足以分配给下一个自然数。
    • 通过 sumtot 变量记录当前和和已分解的数的总个数。
  • 调整分解

    • 如果分解后总和 sum 大于 n + 1,移除一个数。
    • 如果分解后总和 sum 等于 n + 1,调整分解方案以确保所有数不同。
  • 高精度乘法

    • mul(int x) 方法用于将高精度数 s 乘以 x
    • 使用数组 s 存储乘法结果,并处理每位上的进位。
  • 输出

    • 输出分解方案。
    • 输出高精度乘法结果。
import java.util.Scanner;

public class Main {
    // 数组a用于存储分解后的各个部分
    static int[] a = new int[10001];
    // 数组s用于高精度乘法计算
    static int[] s = new int[10001];
    // 用于记录当前高精度数的长度
    static int len = 1;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // 读取输入的整数n
        int n = scanner.nextInt();
        scanner.close();

        // 特殊情况处理,当n为3和4时直接输出结果
        if (n == 3) {
            System.out.println("1 2");
            System.out.println("2");
            return;
        }
        if (n == 4) {
            System.out.println("1 3");
            System.out.println("3");
            return;
        }

        // 初始化高精度乘法的结果,s[0]未用,s[1]置为1
        s[0] = s[1] = 1;
        int sum = 0, tot = 0;
        
        // 贪心分解,将n尽量分解成1, 2, 3, ..., k这些数
        for (int i = 2; sum < n; sum += i, i++) {
            a[++tot] = i;
        }
        
        // 根据剩余情况进行调整
        if (sum > n + 1) {
            a[sum - n - 1] = 0;  // 移除一个数
        } else if (sum == n + 1) {
            a[tot]++;  // 增加最后一个数
            a[1] = 0;  // 移除第一个数
        }

        // 输出分解方案并计算乘积
        for (int i = 1; i <= tot; i++) {
            if (a[i] != 0) {
                System.out.print(a[i] + " ");
                mul(a[i]);  // 高精度乘法
            }
        }
        System.out.println();

        // 输出高精度乘法结果
        for (int i = len; i >= 1; i--) {
            System.out.print(s[i]);
        }
        System.out.println();
    }

    // 高精度乘法,将高精度数s乘以x
    static void mul(int x) {
        // 逐位乘以x
        for (int i = 1; i <= len; i++) {
            s[i] *= x;
        }
        // 处理进位
        for (int i = 1; i <= len; i++) {
            s[i + 1] += s[i] / 10;
            s[i] %= 10;
        }
        // 处理最高位可能产生的新进位
        while (s[len + 1] > 0) {
            len++;
            s[len + 1] += s[len] / 10;
            s[len] %= 10;
        }
    }
}

P1045 [NOIP2003 普及组] 麦森数

解题步骤

解决方案

  1. 计算位数:利用对数公式来计算 2^P - 1 的位数。
  2. 计算最后 500 位数字:使用 BigInteger 进行高精度运算。

步骤

  1. 读取输入的 P。
  2. 使用对数公式计算 2^P - 1 的位数。
  3. 使用 BigInteger 计算 2^P - 1 的值,并取其最后 500 位。
  4. 格式化输出结果。
import java.math.BigInteger;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取输入的 P
        int P = scanner.nextInt();
        
        // 计算 2^P - 1 的位数
        int numDigits = (int) Math.floor(P * Math.log10(2)) + 1;
        
        // 使用 BigInteger 计算 2^P - 1
        BigInteger two = BigInteger.valueOf(2);
        BigInteger mersenneNumber = two.pow(P).subtract(BigInteger.ONE);
        
        // 获取最后 500 位
        BigInteger modulus = BigInteger.TEN.pow(500);
        BigInteger last500Digits = mersenneNumber.mod(modulus);
        
        // 将最后 500 位转换为字符串,并补足 500 位
        String last500Str = last500Digits.toString();
        while (last500Str.length() < 500) {
            last500Str = "0" + last500Str;
        }
        
        // 输出位数
        System.out.println(numDigits);
        
        // 输出最后 500 位,每行 50 位
        for (int i = 0; i < 500; i += 50) {
            System.out.println(last500Str.substring(i, i + 50));
        }
        
        scanner.close();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HeShen.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值