CSP认证-202305

前言

        使用java,根据官方模拟考试的试题列表刷题 试题清单

        目前只更新了前三题的思路,并且第三题跟着找到的满分答案但只得了90分(求佬指点),后面两题先放一放,随缘更新~

202305

202305-1 重复局面

满分思路:Map记录某个局面对应的出现次数,使用StringBuilder拼接每局局面

java:Map查询key是否存在containsKey(key),StringBuilder清空setLength(0)

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        scanner.nextLine();
        Map<String, Integer> situations = new HashMap<>();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < n; i++) {
            for (int t = 0; t < 8; t++) {
                sb.append(scanner.nextLine()); // 每一行
            }
            String temp = sb.toString();
            int time = 1;
            if (situations.containsKey(temp)) time += situations.get(temp);
            situations.put(temp, time);
            System.out.println(time);
            sb.setLength(0); // 清空StringBuilder
        }
    }
}

202305-2 矩阵运算

(1)70分思路:暴力求解,按照题目公式的顺序,每次矩阵运算使用三重循环

(2)满分思路:利用矩阵乘法结合率进行优化,原顺序(Q*K)*V,n*n*d,变顺序Q*(K*V),n*d*d

注意:矩阵运算结果使用long存储

import java.util.Scanner;

public class Main {
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(), d = scanner.nextInt(); // 矩阵大小
        long[][] Q = new long[n][d], K = new long[d][n], V = new long[n][d];
        long[] W = new long[n];
        long[][] resKV = new long[d][d], res = new long[n][d];
        for(int i = 0; i < n; i++){ // Q
            for(int j = 0; j < d; j++){
                Q[i][j] = scanner.nextLong();
            }
        }
        for(int i = 0; i < n; i++){ // K
            for(int j = 0; j < d; j++){
                K[j][i] = scanner.nextLong();
            }
        }
        for(int i = 0; i < n; i++){ // V
            for(int j = 0; j < d; j++){
                V[i][j] = scanner.nextLong();
            }
        }
        for(int i = 0; i < n; i++){
            W[i] = scanner.nextLong();
        }
        for(int i = 0; i < d; i++){
            for(int  j = 0; j < d; j++){
                for(int k = 0; k < n; k++){ // KV
                    resKV[i][j] += K[i][k] * V[k][j];
                }
            }
        }
        for(int i = 0; i < n; i++){
            for(int  j = 0; j < d; j++){
                for(int k = 0; k < d; k++){ // QKV
                    res[i][j] += Q[i][k] * resKV[k][j];
                }
                res[i][j] *= W[i]; // W
                System.out.print(res[i][j]+" ");
            }
            System.out.println();
        }
    }
}

202305-3 解压缩

90分思路:内存超限。只找到了c++的满分版本,就按照思路改成了java版,但是内存超出,不知道问题出在哪里(求佬指点)。使用char[]存储所有被压缩数据,index记录此时处理字符的下标处,逐个判断各种情况;getTwo(char c1,char c2)将两个char表示的一个byte转换为二进制,getSmall(int num)将后面num个小端序的十六进制转为十进制。

java:

        ①二/十六进制String转十进制:Integer.parseInt(String,2/16)

        ②十六进制char转十进制:Character.digit(char,16)

        ③十进制转二进制String:Integer.toBinaryString(int)

                二进制结果始终为四位:String.format("%4s",String).replace(' ','0')

import java.util.*;

public class Main {
    static char[] data; // 被压缩数据

    static int index = 0; // 下标

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int s = scanner.nextInt(); // 被压缩数据字节数
        scanner.nextLine(); // 清空换行符
        StringBuilder res = new StringBuilder(); // 结果
        // 数据
        StringBuilder dataString = new StringBuilder();
        for (int i = 0; i < (s + 7) / 8; i++) dataString.append(scanner.nextLine());
        if (dataString.length() != 2 * s) return; // 长度不一致
        data = dataString.toString().toCharArray();
        // 引导域
        while (index < 8) { // 引导域长度不超过四个字节
            if (getTwo(data[index++], data[index++]).charAt(0) != '1') break; // 首位不为1
        }
        // 数据域
        while (index < s*2) {
            String twoString = getTwo(data[index++], data[index++]); // 获取后两个字符的二进制
            char six = twoString.charAt(6), seven = twoString.charAt(7);
            if (six == '0' && seven == '0') { // 字面量
                int l = Integer.parseInt(twoString.substring(0, 6), 2) + 1; // 随后l个字节
                if (l > 60) l = getSmall(l - 60) + 1; // 存储长度字节小端序
                while (l-- > 0)
                    res.append(data[index++]).append(data[index++]);
            } else if (six == '1' && seven == '1') return; // 不合法
            else { // 回溯引用
                int o = 0, l = 0; // 偏移量、长度
                if (six == '0' && seven == '1') { // 回溯引用1
                    o = Integer.parseInt(twoString.substring(0, 3) + getTwo(data[index++], data[index++]), 2); // 偏移量
                    l = Integer.parseInt(twoString.substring(3, 6), 2) + 4; // 长度
                } else if (six == '1' && seven == '0') { // 回溯引用2
                    o = getSmall(2); // 后两个字节的小端序
                    l = Integer.parseInt(twoString.substring(0, 6), 2) + 1; // 长度
                }
                int size = res.length();
                while (l > o) {
                    res.append(res.substring(size - 2 * o, size));
                    l -= o;
                }
                res.append(res.substring(size - 2 * o, size - 2 * o + 2 * l));
            }
        }
        int size = res.length(), start , end = 0;
        while (end < size) { // 输出
            start = end;
            end = Math.min(end + 16, size);
            System.out.println(res.substring(start, end));
        }
    }

    public static String getTwo(char c1, char c2) { // 十六进制转二进制
        int a = Character.digit(c1, 16), b = Character.digit(c2, 16);
        String s1 = String.format("%4s", Integer.toBinaryString(a)).replace(' ', '0'); // 补零
        String s2 = String.format("%4s", Integer.toBinaryString(b)).replace(' ', '0');
        return s1 + s2;
    }

    public static int getSmall(int num) { // 后num个字节小端序十六进制转二进制
        StringBuilder res = new StringBuilder();
        for (int k = 0; k < num; k++) {
            res.insert(0, data[index + 1]).insert(0, data[index]);
            index += 2;
        }
        return Integer.parseInt(res.toString(), 16);
    }
}

202305总结

        1、第一题字符比较转换为字符串比较,计数使用Map

        2、第二题矩阵乘法的时间复杂度优化

        3、第三题各进制转换

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值