14届蓝桥杯省赛Java A 组Q1~Q3

题目链接:

Q1

蓝桥云课:特殊日期

Q2

蓝桥云课:与或异或

洛谷:P13877 [蓝桥杯 2023 省 Java A] 与或异或

Q3

蓝桥云课:平均

洛谷:P13878 [蓝桥杯 2023 省 Java/Python A] 平均

算法原理:

Q1解法:暴力枚举

时间复杂度O(1)

枚举每个年份、每个月份、每个天数,算出各个数位上的总和进行比较

其中2月份比较特殊,按照闰年的计算规则:四年一闰,百年不闰,四百年再闰

得出判断闰年的代码:(i%4==0&&i%100!=0)||(i%400==0)

Q2解法:递归、搜索与回溯

时间复杂度O(3¹⁰)

将题目的示例转化成数组

会变成

java 复制代码
1 0 1 0 1 //第0行
1 1 1 0   //第1行
1 1 1     //第2行
1 0       //第3行
1         //第4行

我们发现第1行第1个元素是由第0行第1个元素和第0行第2个元素决定的

第1行第2个元素是由第0行第2个元素和第0行第3个元素决定的

......

第2行第1个元素是由第1行第1个元素和第1行第2个元素决定的

......

因此大规模的问题可以分成相似的子问题来解决,所以我们采用递归的解法

由于针对每两个数有3种选择方式:&、|、^,因此我们要采用回溯的方法来逐个尝试当前位置分别采用&、|、^得出的结果

其实这里类似用到了隐式回溯,因为在数组中可以直接覆盖掉数据,达到"回溯"的效果

类似题目如下👇

A.每日一题:1415. 长度为 n 的开心字符串中字典序第 k 小的字符串

A.每日一题------1980. 找出不同的二进制字符串

E.位运算-基础------3211. 生成不含相邻零的二进制字符串

A.每日一题:3129. 找出所有稳定的二进制数组 I +3130. 找出所有稳定的二进制数组 II

显式回溯与隐式回溯的区别

底层都是回溯思想,只是写法随容器变而已

①固定长度结构(char []、数组)→ 天然适合隐式回溯,写法更干净

②变长结构(StringBuffer、List、Builder)→ 必须显式回溯,不然必错

具体步骤:

Ⅰ按题目要求初始化第0行

Ⅱdfs方法设计:

①如果到了第5行,说明第4行第一个数即为结果,如果是1,方案数+1

②填写当前位置ret[i][j]的值:取决于ret[i-1][j]和ret[i-1][j+1]

分别填写ret[i-1][j]&ret[i-1][j+1]、ret[i-1][j] | ret[i-1][j+1]、ret[i-1][j]^ret[i-1][j+1]的结果

③填写完后判断当前位置是否是当前行的最后一个位置

如果是最后一个位置:开启下一行,从第1个位置开始填,否则就继续填当前行的下一个位置

Q3解法:贪心

时间复杂度O(n logn)

思路很简单,我们要保证0~9每个数都出现n/10次,那么为了保证总的代价和最小,肯定要移除代价小的

因此我们做出决定:

①用大小为10的数组表示数字0~9,将它们出现的代价挂在后面

②为了保留代价大的,移除代价小的,通过降序排序实现

图解如下👇

其中对顺序表降序排序直接用:Collections.sort(nums[i],Collections.reverseOrder());

关键易错点复盘

①创建大小为10的数组,其中每个元素是一个顺序表(此题的形式):

java 复制代码
List<Integer>[] nums=new ArrayList[10];

及时初始化,创建空顺序表:

java 复制代码
for(int i=0;i<10;i++) nums[i]=new ArrayList<>();

②创建一个顺序表,其中每个元素是大小为10的数组:

java 复制代码
List<int[]> list=new ArrayList<>();

及时初始化,添加数组

java 复制代码
list.add(new int[10]);//第一个元素
list.add(new int[10]);//第二个元素
list.add(new int[10]);//第三个元素
//赋值过程
list.get(0)[5]=999;
list.get(1)[9]=666;

Java代码:

Q1

java 复制代码
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        int ret=0;
        for(int i=1900;i<9999;i++){//枚举年份
            //计算年份各位的和
            String s=i+"";
            int sum=0;
            for(char c:s.toCharArray()) sum+=c-'0';
            for(int j=1;j<=12;j++){//枚举月份
                int n=0;//确定天数
                if(j==1||j==3||j==5||j==7||j==8||j==10||j==12) n=31;
                else if(j==2){
                    //闰年
                    boolean isleap=(i%4==0&&i%100!=0)||(i%400==0);
                    if(isleap) n=29;
                    //平年
                    else n=28;
                }else n=30;
                for(int k=1;k<=n;k++){
                    if(sum==getsum(j)+getsum(k)) ret++;
                }
            }
        }
        System.out.println(ret);
    }
    //获取各数位上的和
    private static int getsum(int n){
        int ret=0;
        while(n>0){
            ret+=n%10;
            n/=10;
        }
        return ret;
    }
}

Q2

java 复制代码
import java.util.*;
public class Main{
    private static int cnt=0;
    public static void main(String[] args){
        int[][] ret=new int[5][5];
        ret[0][0]=1;
        ret[0][1]=0;
        ret[0][2]=1;
        ret[0][3]=0;
        ret[0][4]=1;
        //从第1行第0个数开始计算
        dfs(ret,1,0);
        System.out.println(cnt);
    }
    private static void dfs(int[][] ret,int i,int j){
        if(i==5){
            cnt+=ret[4][0]==1?1:0;
            return;
        }
        //k=0:&  k=1:|  k=2:^
        for(int k=0;k<3;k++){
            if(k==0) ret[i][j]=ret[i-1][j]&ret[i-1][j+1];
            else if(k==1) ret[i][j]=ret[i-1][j]|ret[i-1][j+1];
            else ret[i][j]=ret[i-1][j]^ret[i-1][j+1];
            //判断j是不是当前行最后一个节点
            if(j==4-i) dfs(ret,i+1,0);
            else dfs(ret,i,j+1);
        }
    }
}

Q3

java 复制代码
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int t=n/10;
        long ret=0;
        List<Integer>[] nums=new ArrayList[10];
        //初始化每个位置为一个空顺序表
        for(int i=0;i<10;i++) nums[i]=new ArrayList<>();
        for(int i=0;i<n;i++){
            int a=sc.nextInt();
            int b=sc.nextInt();
            nums[a].add(b);
        }
        //对数组中的每个顺序表降序排序
        for(int i=0;i<10;i++){
            if(nums[i].size()<=t) continue;
            Collections.sort(nums[i],Collections.reverseOrder());
            for(int j=t;j<nums[i].size();j++) ret+=nums[i].get(j);
        }
        System.out.println(ret);
        sc.close();
    }
}
相关推荐
钮钴禄·爱因斯晨1 小时前
他到底喜欢我吗?赛博塔罗Java+前端实现,一键解答!
java·开发语言·前端·javascript·css·html
词元Max1 小时前
Java 转 AI Agent 开发学习路线(2026年3月最新版)
java·人工智能·学习
亚历克斯神1 小时前
Java 云原生开发最佳实践:构建现代化应用
java·spring·微服务
布说在见1 小时前
企业级 Java 登录注册系统构建指南(附核心代码与配置)
java·开发语言
是宇写的啊1 小时前
SpringBoot配置文件
java·spring boot·spring
草莓熊Lotso1 小时前
一文读懂 Java 主流编译器:特性、场景与选择指南
java·开发语言·经验分享
Y001112362 小时前
Maven
java·maven
不吃香菜5672 小时前
cloudcode入门学习
java·windows·cloudcode
疯狂成瘾者2 小时前
Java 常见 Map 对比总结:HashMap、LinkedHashMap、TreeMap、ConcurrentHashMap
java·开发语言·spring