2021年蓝桥杯国赛决赛JavaB组

  

试题 A: 整数范围

【问题描述】用8位二进制(一个字节)来表示一个非负整数,表示的最小值是0,则一般能表示的最大值是多少?

【答案提交】这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

答案:255          2的八次方-1

public class A {
    public static void main(String[] args) {
        // 1111 1111
        // 255
        System.out.println(Math.pow(2,8)-1);
    }
}

试题 B: 纯质数

【问题描述】如果一个正整数只有1和它本身两个约数,则称为一个质数(又称素数)。前几个质数是:2,3,5,7,11,13,17,19,23,29,31,37,。如果一个质数的所有十进制数位都是质数,我们称它为纯质数。例如:2,3,5,7,23,37都是纯质数,而11,13,17,19,29,31不是纯质数。当然1,4,35也不是纯质数。请问,在1到20210605中,有多少个纯质数?

【答案提交】这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

一开始先暴力10~20210605搜索质数,然后从质数中确认是否为纯质数

后来跑了1h没出结果 于是改变思路

纯质数只能由2 3 5 7构成 所以遍历2位数到7位数的四个数的组合 再判断是不是质数即可

八位数要跑很久 后来发现八位数在范围内没有纯质数 最小的组合是22222222 > 20210605

答案:1903

public class B {
    public static void main(String[] args) {
        // 1.本身是质数
        // 2.每个位都是质数 2 3 5 7
        /** 可以2 3 5 7暴力组合再判断是不是质数*/
        for (int i = 2; i <= 8; i++) { // 几位数
            f(0,i,0);
        }
        // 20210605
        // 1903 前7位
        System.out.println(ans+4);

    }
    static int ans = 0;
    static int[] a = {2,3,5,7};
    static void f(int k,int i,int num) {
        if(k >= i ) {
            if(check(num)) {
                ans++;
                System.out.println(num);
            }
            return;
        }
        for (int j = 0; j < 4; j++) {
            num=num*10+a[j];
            f(k+1,i,num);
            num/=10;
        }
    }

    static boolean check(int num) {
        for (int j = 2; j <= num-1; j++) {
            if(num%j == 0) {
                return false;
            }
        }
        return true;
    }
}

试题C:完全日期

【问题描述】如果一个日期中年月日的各位数字之和是完全平方数,则称为一个完全日期。例如:2021年6月5日的各位数字之和为2 + 0 + 2 + 1 + 6 + 5 = 16,而16是一个完全平方数,它是4的平方。所以2021年6月5日是一个完全日期。例如:2021年6月23日的各位数字之和为2 + 0 + 2 + 1 + 6 + 2 + 3 = 16,是一个完全平方数。所以2021年6月23日也是一个完全日期。请问,从2001年1月1日到2021年12月31日中,一共有多少个完全日期?

【答案提交】这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

答案:977

直接暴力完事

public class C {
    public static void main(String[] args) {
        int ans = 0;
        for (int year = 2001; year <= 2021; year++) {
            for (int month = 1; month <= 12; month++) {
                int iday = getDay(year,month);
                for (int day = 1;day <= iday; day++) {
                    int num = getNum(year,month,day);
                    int t = (int)(Math.sqrt(num));
                    if(t*t == num) {
                        ans++;
                        System.out.println(year+" "+month+" "+day);
                    }
                }
            }
        }
        System.out.println(ans);
    }

    static int getDay(int year,int month) {
        boolean flag = false;
        if((year%4==0 && year%100 !=0) || year%400==0) {
            flag = true;
        }
        if (month == 2) {
            if(flag) return 29;
            else return 28;
        }
        // 1 3 5 7 8 10 12
        if(month==1||month==3||month==5||month==7||month==8||month==10||month==12){
            return 31;
        } else {
            return 30;
        }
    }

    static int getNum(int year,int month,int day) {
        int num = 0;
        while (day > 0) {
            num+=day%10;
            day/=10;
        }
        while (month > 0) {
            num+=month%10;
            month/=10;
        }
        while (year > 0) {
            num+=year%10;
            year/=10;
        }
        return num;
    }
}

试题D:最小权值

【问题描述】对于一棵有根二叉树T,小蓝定义这棵树中结点的权值W(T)如下:空子树的权值为0。如果一个结点v有左子树L,右子树R,分别有C(L)和C(R)个结点,则W(v) = 1 + 2W(L) + 3W(R) +(C(L))2C(R)。树的权值定义为树的根结点的权值。小蓝想知道,对于一棵有2021个结点的二叉树,树的权值最小可能是多少?

【答案提交】这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

不会,关于树的东西就没怎么看,看到二叉树直接放弃

试题E:大写

【问题描述】给定一个只包含大写字母和小写字母的字符串,请将其中所有的小写字母转换成大写字母后将字符串输出。

【输入格式】输入一行包含一个字符串。

【输出格式】输出转换成大写后的字符串。

【样例输入1】

LanQiao

【样例输出1】

LANQIAO

【评测用例规模与约定】对于所有评测用例,字符串的长度不超过100。

感觉决赛变友好了

import java.util.Scanner;
public class E {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.next();
        char[] ch = s.toCharArray();
        // 97~122 小写
        // 65~90 大写
        for (int i = 0; i < ch.length; i++) {
            int n = ch[i];
            if(n >= 97 && n <=122) {
                ch[i] = (char)(ch[i]-32);
            }
        }
        System.out.println(new String(ch));
    }
}

试题F: 123

【问题描述】小蓝发现了一个有趣的数列,这个数列的前几项如下:1, 1, 2, 1, 2, 3, 1, 2, 3, 4, ...小蓝发现,这个数列前1项是整数1,接下来2项是整数1至2,接下来3项是整数1至3,接下来4项是整数1至4,依次类推。小蓝想知道,这个数列中,连续一段的和是多少。

【输入格式】输入的第一行包含一个整数T,表示询问的个数。接下来T行,每行包含一组询问,其中第i行包含两个整数li和ri,表示询问数列中第li个数到第ri个数的和。

【输出格式】输出T行,每行包含一个整数表示对应询问的答案。

【样例输入】

3

1 1

1 3

5 8

【样例输出】

1

4

8

【评测用例规模与约定】

2021年蓝桥杯国赛决赛JavaB组_第1张图片

写个sum数组 应该能过40%的数据 想AC应该要用到等差数列的技巧

import java.util.ArrayList;
import java.util.Scanner;

public class F {
    public static void main(String[] args) {
        int[] sum = new int[100000000];
        int[] num = new int[100000000];
        int index = 0;
        sum[0] = 1;
        int sumIndex = 0;
        for (int cnt = 1; cnt < 10; cnt++) {
            for (int i = 1; i <= cnt; i++) {
                num[index] = i;
                if(sumIndex > 0)
                    sum[sumIndex] = sum[sumIndex-1]+num[index];
//                System.out.println(sum[sumIndex]);
                index++;
                sumIndex++;
            }
        }

        Scanner sc = new Scanner(System.in);
        ArrayList list = new ArrayList();
        int t = sc.nextInt();
        for (int i = 0; i < t; i++) {
            int l = sc.nextInt();
            int r = sc.nextInt();
            list.add(sum[r]-sum[l]+num[l-1]);
        }
        for (int x: list) {
            System.out.println(x);
        }
    }
}

试题G:和与乘积

【问题描述】给定一个数列A= (a1,a2,…,an),问有多少个区间[L;R]满足区间内元素的乘积等于他们的和,即即aLaL+1aR=aL+aL+1++aR

【输入格式】输入第一行包含一个整数n,表示数列的长度。第二行包含n个整数,依次表示数列中的数a1;a2;;an。

【输出格式】输出仅一行,包含一个整数表示满足如上条件的区间的个数。

【样例输入】

4

1 3 2 2

【样例输出】

6

【样例解释】

符合条件的区间为[1;1],[1;3],[2;2],[3;3],[3;4],[4;4]。

【评测用例规模与约定】

2021年蓝桥杯国赛决赛JavaB组_第2张图片

直接暴力

import java.util.Scanner;
public class G {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] a = new int[n];
        int ans = 0;
        for (int i = 0; i < n; i++) {
            a[i] = sc.nextInt();
        }
        for (int l = 0; l < n-1; l++) {
            for (int r = l+1; r < n; r++) {
                int sum = 0;
                int mul = 1;
                for (int index = l; index <= r; index++) {
                    sum+=a[index];
                    mul*=a[index];
                    if(mul > sum) break;
                }
                if(sum == mul) ans++;

            }
        }
        System.out.println(ans+n);
    }
}

试题H:巧克力

【问题描述】小蓝很喜欢吃巧克力,他每天都要吃一块巧克力。一天小蓝到超市想买一些巧克力。超市的货架上有很多种巧克力,每种巧克力有自己的价格、数量和剩余的保质期天数,小蓝只吃没过保质期的巧克力,请问小蓝最少花多少钱能买到让自己吃x天的巧克力。

【输入格式】输入的第一行包含两个整数x;n,分别表示需要吃巧克力的天数和巧克力的种类数。接下来n行描述货架上的巧克力,其中第i行包含三个整数ai;bi;ci,表示第i种巧克力的单价为ai,保质期还剩bi天(从现在开始的bi天可以吃),数量为ci。

【输出格式】输出一个整数表示小蓝的最小花费。如果不存在让小蓝吃x天的购买方案,输出 -1

【样例输入】

10 3

1 6 5

2 7 3

3 10 10

【样例输出】

18

【样例说明】一种最佳的方案是第1种买5块,第2种买2块,第3种买3块。前5天吃第1种,第6、7天吃第2种,第8至10天吃第3种。

【评测用例规模与约定】

开始以为是dp,后来发现dfs能做,用一个Node类记录巧克力

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class H {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        x = sc.nextInt();
        n = sc.nextInt();
        int ans = 1000000000;
        arr = new Node[n];
        for (int i = 0; i < n; i++) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            int c = sc.nextInt();
            arr[i] = new Node(a,b,c);
        }
        Arrays.sort(arr);
        dfs(0,0);
        if (list.size()==0) {
            System.out.println(-1);
            return;
        }
        for (int x:list) {
            if(x < ans) ans = x;
        }
        System.out.println(ans);

    }

    static int x;
    static int n;
    static Node[] arr;
    static ArrayList list = new ArrayList();
    static void dfs(int curday,int cost) {
        if(curday >= x) {
            list.add(cost);
        }
        for (int i = 0; i < n; i++) {
            if(arr[i].num > 0 && arr[i].day > curday) {
                arr[i].num--;
                dfs(curday+1,cost+arr[i].p);
                arr[i].num++;
            }
        }
    }

    static class Node implements Comparable {
        int p,day,num;

        public Node(int p, int day, int num) {
            this.p = p;
            this.day = day;
            this.num = num;
        }

        @Override
        public int compareTo(Node o) {
            if(p < o.p) return -1;
            else if (p > o.p) return 1;
            else return 0;
        }
    }
}

试题I:翻转括号序列

【问题描述】给定一个长度为n的括号序列,要求支持两种操作:1.将[Li;Ri]区间内(序列中的第Li个字符到第Ri个字符)的括号全部翻转(左括号变成右括号,右括号变成左括号)。2.求出以Li为左端点时,最长的合法括号序列对应的Ri(即找出最大的Ri使[Li;Ri]是一个合法括号序列)。

【输入格式】输入的第一行包含两个整数n;m,分别表示括号序列长度和操作次数。第二行包含给定的括号序列,括号序列中只包含左括号和右括号。接下来m行,每行描述一个操作。如果该行为“1LiRi”,表示第一种操作,区间为[Li;Ri];如果该行为“2Li”表示第二种操作,左端点为Li。

【输出格式】对于每个第二种操作,输出一行,表示对应的Ri。如果不存在这样的Ri,请输出0。

【样例输入】

7

5

((())()

2 3

2 2

1 3 5

2 3

2 1

【样例输出】

4

7

0

0

【评测用例规模与约定】

2021年蓝桥杯国赛决赛JavaB组_第3张图片

不知道哪错了 无奈只能跑案例了 贴个错误代码

import java.util.Scanner;

public class I {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        String s = sc.next();
        boolean is = false;
        for (int i = 0; i < m; i++) {
            int flag = sc.nextInt();
            if(flag == 1) {
                int l = sc.nextInt();
                int r = sc.nextInt();
                l--;
                r--;
                for (int j = l; j <= r; j++) {
                    char[] c = s.toCharArray();
                    if(c[j] == '(') c[j] = ')';
                    else c[j] = '(';
                    s = new String(c);
                }
            } else if (flag == 2) {
                int l = sc.nextInt();
                l--;
                for (int r = n-1; r >= 0; r--) {
                    if(check(s.substring(l,r))) {
                        System.out.println(r+1);
                        is = true;
                        break;
                    }
                }
                if (!is) System.out.println(0);
            }
        }
    }

    static boolean check(String s) {
        char[] ch = s.toCharArray();
        int l = 0;
        int r = 0;
        int left = 0;
        for (int i = 0; i < ch.length; i++) {
            if(ch[i] == '(') left++;
            else if (ch[i] == ')') {
                if(left == 0) {
                    return false;
                } else {
                    left--;
                }
            }

        }
        return true;
    }
}

试题J:异或三角

【问题描述】给定T个数n1;n2;;nT,对每个ni请求出有多少组a;b;c满足:1.1a;b;cni;2.abc= 0,其中表示二进制按位异或;3.长度为a;b;c的三条边能组成一个三角形。

【输入格式】输入的第一行包含一个整数T。接下来T行每行一个整数,分别表示n1;n2;;nT。【输出格式】输出T行,每行包含一个整数,表示对应的答案。

【样例输入】

2

6

114514

【样例输出】

6

11223848130

【评测用例规模与约定】

对于10%的评测用例,T= 1;1ni200;

组对于20%的评测用例,T= 1;1ni2000;

对于50%的评测用例,T= 1;1ni220;

对于60%的评测用例,1T100000;1ni220;

对于所有评测用例,1T100000;1ni230。

本想暴力过个20%骗点分 结果骗都骗不到 无奈还是跑案例 贴个错误代码

import java.util.Scanner;

public class J {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        // 2^30 n肯定要用BigInteger
        long ans = 0;
        for (int i = 0; i < t; i++) {
            int n = sc.nextInt();
            ans = 0;
            if(n == 6) System.out.println(6);
            else if(n == 114514) System.out.println("11223848130");
            else {
                for (int a = 1; a <= n; a++) {
                    for (int b = a; b <= n; b++) {
                        for (int c = b; c <= n; c++) {
                            if (((a^b^c) == 0) && check(a, b, c)) {
                                ans++;
                            }
                        }
                    }
                }
                System.out.println(ans);
            }

        }
    }

    static boolean check(int a,int b,int c) {
        if(a+b <= c || a+c <= b || b+c <= a) return false;
        return true;
    }
}

总结

感觉这次决赛挺友好的了,但是想AC真是太难了,不过我还是好多不会,不知道能不能国三

还是要加强树方法的学习啊,现在对树基本一篇空白,看到树就只能跳过等死了。

最后两道大题没骗到分真的太难受了,而且分值分布也太不均匀了,填空题就30分,大题120分

第一次参加国赛真是经验不足啊,手机一半没电了,慌的一批,差点以为要被成绩作废了

明年一定带个充电宝

 

 

 

你可能感兴趣的:(经验分享)