2016-2022年蓝桥B组省赛第3题汇总讲解

总结:

2016:凑算法 全排列、递归、数学思维、注意细节(除法小小数问题)

2017:承压计算 找规律、注意细节(最边缘重量计算、除法运算要用double类型存数据)、精确度

2018:复数幂 数学思维、找规律

2019:数列求值 找规律、思维分析

2020-1:合并检测 数学思维(均值不等式)

2020-2:蛇形填数 找规律

2021:直线 数学思维、递归

2022:字符统计 ascll码与字符间转换、思维分析

综上:

蓝桥第3题也会存在一些大数据或者找规律的题型,但总体更偏向数学思维分析,通过数学思维分析题目,找出突破点会使解题轻松很多。并且对代码细节上的要求也更高了。

主要考察:
  1. 递归、全排列。

注意全排列时重复情况,如果题目要求不能重复,结果就需要去重。

(如:2016、2021)

  1. 数学分析

公式转换、精确度、复数运算、大数求和低位不受高位影响、均值不等式、平面几何思维

(如:2016、2017、2018、2019、2020-1、2021)

  1. 找规律

认真读题、抠字眼。注意给出的示例也很重要,认真看。

(如:2017、2018、2019、2020-2)

  1. 字符串

字符与数字之间的转换

(如:2022年)

  1. 细节

数据精确度、除法造成精度不准的时候将除法转换为乘法

(如:2016、2017)

接下来列出2016-2022年间第三题的详细讲解


2016年

B DEF

A + --- + ------- = 10

​ C GHI

这个算式中A~I代表1~9的数字,不同的字母代表不同的数字。

比如:

6+8/3+952/714 就是一种解法,

5+3/1+972/486 是另一种解法。

这个算式一共有多少种解法?

注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。

static int[] a={1,2,3,4,5,6,7,8,9};
static int count=0;
public static void main(String[] args){
    f(0);
    System.out.println(count);
}
public static void f(int k){
    if(k>=9){
        int A=a[0];
        int B=a[1];
        int C=a[2];
        int D=a[3]*100+a[4]*10+a[5];
        int E=a[6]*100+a[7]*10+a[8];
        if(B*E + C*D == (10 - A) * C * E)count++;
    }
    for(int i=k;i<9;i++)//全排列
    {
     swap(i,k);
     f(k+1);
     swap(i,k);
    }
}
public static void swap(int i,int k){
    int t=a[i];
    a[i]=a[k];
    a[k]=t;
}
答案:29

思路:递归全排列出所有可能的情况的同时,对每种情况判断分析,符合要求则计数。

注意:这道题目的公式中存在除法,存在除法就会有结果为小数,有小数就会存在误差。

所以,为了避免误差需要将除法公式转换为只有乘法的公式再进行计算。

详解请移步:凑算法

2017年

X星球的高科技实验室中整齐地堆放着某批珍贵金属原料。每块金属原料的外形、尺寸完全一致,但重量不同。金属材料被严格地堆放成金字塔形。

                              7 
                             5 8 
                            7 8 8 
                           9 2 7 2 
                          8 1 4 9 1 
                         8 1 8 8 4 1 
                        7 9 6 1 4 5 4 
                       5 6 5 5 6 9 5 6 
                      5 5 4 7 9 3 5 5 1 
                     7 5 7 9 7 4 7 3 3 1 
                    4 6 4 5 5 8 8 3 2 4 3 
                   1 1 3 3 1 6 6 5 5 4 4 2 
                  9 9 9 2 1 9 1 9 2 9 5 7 9 
                 4 3 3 7 7 9 3 6 1 3 8 8 3 7 
                3 6 8 1 5 3 9 5 8 3 8 1 8 3 3 
               8 3 2 3 3 5 5 8 5 4 2 8 6 7 6 9 
              8 1 8 1 8 4 6 2 2 1 7 9 4 2 3 3 4 
             2 8 4 2 2 9 9 2 8 3 4 9 6 3 9 4 6 9 
            7 9 7 4 9 7 6 6 2 8 9 4 1 8 1 7 2 1 6 
           9 2 8 6 4 2 7 9 5 4 1 2 5 1 7 3 9 8 3 3 
          5 2 1 6 7 9 3 2 8 9 5 5 6 6 6 2 1 8 7 9 9 
         6 7 1 8 8 7 5 3 6 5 4 7 3 4 6 7 8 1 3 2 7 4 
        2 2 6 3 5 3 4 9 2 4 5 7 6 6 3 2 7 2 4 8 5 5 4 
       7 4 4 5 8 3 3 8 1 8 6 3 2 1 6 2 6 4 6 3 8 2 9 6 
      1 2 4 1 3 3 5 3 4 9 6 3 8 6 5 9 1 5 3 2 6 8 8 5 3 
     2 2 7 9 3 3 2 8 6 9 8 4 4 9 5 8 2 6 3 4 8 4 9 3 8 8 
    7 7 7 9 7 5 2 7 9 2 5 1 9 2 6 5 3 9 3 5 7 3 5 4 2 8 9 
   7 7 6 6 8 7 5 5 8 2 4 7 7 4 7 2 6 9 2 1 8 2 9 8 5 7 3 6 
  5 9 4 5 5 7 5 5 6 3 5 3 9 5 8 9 5 4 1 2 6 1 4 3 5 3 2 4 1 
 X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X 

其中的数字代表金属块的重量(计量单位较大)。最下一层的X代表30台极高精度的电子秤。

假设每块原料的重量都十分精确地平均落在下方的两个金属块上,最后,所有的金属块的重量都严格精确地平分落在最底层的电子秤上。电子秤的计量单位很小,所以显示的数字很大。工作人员发现,其中读数最小的电子秤的示数为:2086458231。请你推算出:读数最大的电子秤的示数为多少?

注意:需要提交的是一个整数,不要填写任何多余的内容。

public static void main(String[] args){
    double[][] a={
                {7},
                {5, 8},
                {7, 8, 8},
                {9, 2, 7, 2},
                {8, 1, 4, 9, 1},
                {8, 1, 8, 8, 4, 1},
                {7, 9, 6, 1, 4, 5, 4},
                {5, 6, 5, 5, 6, 9, 5, 6},
                {5, 5, 4, 7, 9, 3, 5, 5, 1},
                {7, 5, 7, 9, 7, 4, 7, 3, 3, 1},
                {4, 6, 4, 5, 5, 8, 8, 3, 2, 4, 3},
                {1, 1, 3, 3, 1, 6, 6, 5, 5, 4, 4, 2},
                {9, 9, 9, 2, 1, 9, 1, 9, 2, 9, 5, 7, 9},
                {4, 3, 3, 7, 7, 9, 3, 6, 1, 3, 8, 8, 3, 7},
                {3, 6, 8, 1, 5, 3, 9, 5, 8, 3, 8, 1, 8, 3, 3},
                {8, 3, 2, 3, 3, 5, 5, 8, 5, 4, 2, 8, 6, 7, 6, 9},
                {8, 1, 8, 1, 8, 4, 6, 2, 2, 1, 7, 9, 4, 2, 3, 3, 4},
                {2, 8, 4, 2, 2, 9, 9, 2, 8, 3, 4, 9, 6, 3, 9, 4, 6, 9},
                {7, 9, 7, 4, 9, 7, 6, 6, 2, 8, 9, 4, 1, 8, 1, 7, 2, 1, 6},
                {9, 2, 8, 6, 4, 2, 7, 9, 5, 4, 1, 2, 5, 1, 7, 3, 9, 8, 3, 3},
                {5, 2, 1, 6, 7, 9, 3, 2, 8, 9, 5, 5, 6, 6, 6, 2, 1, 8, 7, 9, 9},
                {6, 7, 1, 8, 8, 7, 5, 3, 6, 5, 4, 7, 3, 4, 6, 7, 8, 1, 3, 2, 7, 4},
                {2, 2, 6, 3, 5, 3, 4, 9, 2, 4, 5, 7, 6, 6, 3, 2, 7, 2, 4, 8, 5, 5, 4},
                {7, 4, 4, 5, 8, 3, 3, 8, 1, 8, 6, 3, 2, 1, 6, 2, 6, 4, 6, 3, 8, 2, 9, 6},
                {1, 2, 4, 1, 3, 3, 5, 3, 4, 9, 6, 3, 8, 6, 5, 9, 1, 5, 3, 2, 6, 8, 8, 5, 3},
                {2, 2, 7, 9, 3, 3, 2, 8, 6, 9, 8, 4, 4, 9, 5, 8, 2, 6, 3, 4, 8, 4, 9, 3, 8, 8},
                {7, 7, 7, 9, 7, 5, 2, 7, 9, 2, 5, 1, 9, 2, 6, 5, 3, 9, 3, 5, 7, 3, 5, 4, 2, 8, 9},
                {7, 7, 6, 6, 8, 7, 5, 5, 8, 2, 4, 7, 7, 4, 7, 2, 6, 9, 2, 1, 8, 2, 9, 8, 5, 7, 3, 6},
                {5, 9, 4, 5, 5, 7, 5, 5, 6, 3, 5, 3, 9, 5, 8, 9, 5, 4, 1, 2, 6, 1, 4, 3, 5, 3, 2, 4, 1}};
        double[] w=new double[30];
        double max;
        double min;
        for(int i=1;i<a.length;i++){
            for(int j=0;j<a[i].length;j++){
                if(j==0)a[i][0]+=a[i-1][0]/2;//最边缘的只平分上一行最边缘的重量
                else if(j==a[i].length-1)a[i][j]+=a[i-1][j-1]/2;
                else a[i][j]+=a[i-1][j-1]/2+a[i-1][j]/2;//不在边缘的平分左上和正上方的重量
            }
        }
        max=min=a[28][0]/2;
        for(int i=1;i<30;i++){//对最后一行体重秤进行赋值
            if(i==0)w[i]=a[28][0]/2;//左边缘赋值
            else if(i==29)w[i]=a[28][28]/2;//右边缘赋值
            else w[i]=a[28][i]/2+a[28][i-1]/2;//其他赋值

            if(w[i]>max)max=w[i];//找最大值
            if(w[i]<min)min=w[i];//找最小值
        }
        System.out.println(max);
        System.out.println(min);
        System.out.println(max/min*2086458231);
}
答案:7.2665192664E10

思路:将数组每行每个数的重量平分给下一行,反复循环,一直累加到最后一行。

规律:下面每个重量=自身重量+正上方重量/2+左上方重量/2

2018年

设i为虚数单位。对于任意正整数n,(2+3i)^n 的实部和虚部都是整数

求 (2+3i)^123456 等于多少? 即(2+3i)的123456次幂,这个数字很大,要求精确表示。

答案写成 “实部±虚部i” 的形式,实部和虚部都是整数(不能用科学计数法表示),中间任何地方都不加空格,实部为正时前面不加正号。(2+3i)^2 写成: -5+12i,(2+3i)^5 的写成: 122-597i

public static void main(String[] args){
    long x=123456;
    long a=2,b=3,c=2,d=3;
    long n=a,m=b;
    for(int i=1;i<x;i++){
        n=a*c-b*d;
        m=a*d+b*c;
//        System.out.printf("a=%d,b=%d\n",n,m);
        a=n;
        b=m;
    }
if(m<0)
    System.out.println(n+""+m+"i");
else
    System.out.println(n+"+"+m+"i");
}
答案:4043220979119144065-7374402350132176768i

思路:通过循环进行累乘求幂,最终得到结果

规律:(a*bi)*(c*di)=((a*c)-(b*d))+(a*d+b*c)i

注意:由于结果数值非常大,一定要用long型存数据,否则出来的答案不对。

结尾输出要做一下处理,否则答案不通过。

2019年

给定数列 1, 1, 1, 3, 5, 9, 17, …,从第 4 项开始,每项都是前 3 项的和。求第 20190324 项的最后 4 位数字。

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个 4 位整数(提示:答案的千位不为 0),在提交答案时只填写这个整数,填写多余的内容将无法得分。

public static void main(String[] args){
    int[] a=new int[20190325];
    int i;
    a[0]=a[1]=a[2]=1;
    for (i=3;i<20190324;i++){
        a[i]=(a[i-3]+a[i-2]+a[i-1])%10000;//每次低四位求和得到的仍然取低四位
//        System.out.println(a[i]);
    }
    System.out.println(a[i-1]);
}
答案:4659
思路:类似斐波那契数,循环求得前三项和的低四位并保存,再循环运算。

此题类似于斐波那契数列,但是所求20190324项的最后四位数字,要是单纯按照斐波那契数列的思想求下去,别说long类型,BigInteger类型都存不了这么大的数,然后我们发现,所求20190324项的最后四位数字(也就是变相的告诉我们运算过程只和每个数的后四位有关系),那么我们只需要保留每次运算结果的后四位就OK了,这样绝对不会溢出。

注意:一定要去理解%10000什么意思。就类似于你要取后三位数,无论多大的数多少个数进行求和,永远都是这几个数字的低三位求和得到最终的低三位数。

(比如2119+2220+2321+2422求这4个数和的低3位,就相当于只需要119+220+321+422=1082,再对1082%1000=082得到后三位)

2020年-1

新冠疫情由新冠病毒引起,最近在 A 国蔓延,为了尽快控制疫情,A 国准备给大量民众进病毒核酸检测。然而,用于检测的试剂盒紧缺。为了解决这一困难,科学家想了一个办法:合并检测。即将从多个人(k 个)采集的标本放到同一个试剂盒中进行检测。如果结果为阴性,则说明这 k个人都是阴性,用一个试剂盒完成了 k 个人的检测。如果结果为阳性,则说明至少有一个人为阳性,需要将这 k 个人的样本全部重新独立检测(从理论上看,如果检测前 k − 1 个人都是阴性可以推断出第 k 个人是阳性,但是在实际操作中不会利用此推断,而是将 k 个人独立检测),加上最开始的合并检测,一共使用了 k + 1 个试剂盒完成了 k 个人的检测。A 国估计被测的民众的感染率大概是 1%,呈均匀分布。请问 k 取多少能最节省试剂盒?

(这道题需要用数学解题,由于本人数学不太好,所以直接借用其他博主的答案供大家参考)

均值不等式:

假设A国有n个人,感染者有n/100,每k个人一组,共n/k组,共用n/k瓶试剂,按照最坏的情况,每多出一个感染者就多用k瓶试剂,因此共用n/k+(n/100)*k瓶试剂n是定值,所以求(1/k+k/100)最小由于a+b>=2√ab,当且仅当a = b时,取等号,即1/k=k/100时,取得最小值。

解得k = 10

答案:10

思路:可以通过数学计算得到。也可以通过常识得到。做过核酸的应该都知道一管只能装10只拭子吧。

2020年-2

如下图所示,小明用从 1 开始的正整数“蛇形”填充无限大的矩阵。

1 2 6 7 15 …

3 5 8 14 …

4 9 13 …

10 12 …

11 …

容易看出矩阵第二行第二列中的数是 5。请你计算矩阵中第 20 行第 20 列

的数是多少?

public static void main(String[] args){
    int a=1;
    for(int i=1;i<20;i++){
        a+=4*i;
    }
    System.out.println(a);
}
答案:761

思路:题目中给出了提示,第二行第二列是5,再通过观察发现对角线上每个数之间相差4的倍数,且有规律增长。根据这个规律可以求得最终结果

规律:对角线上呈等比数列。

2021年

在平面直角坐标系中,两点可以确定一条直线如果有多点在一条直线上,那么这些点中任意两点确定的直线是同一条

给定平面上2 × 3 个整点{(x, y)|0 ≤ x < 2, 0 ≤ y < 3, x ∈ Z, y ∈ Z},即横坐标是0 到1 (包含0 和1) 之间的整数、纵坐标是0 到2 (包含0 和2) 之间的整数的点。这些点一共确定了11 条不同的直线。

给定平面上20 × 21 个整点{(x, y)|0 ≤ x < 20, 0 ≤ y < 21, x ∈ Z, y ∈ Z},即横坐标是0 到19 (包含0 和19) 之间的整数、纵坐标是0 到20 (包含0 和20) 之间的整数的点。

请问这些点一共确定了多少条不同的直线。

public static void main(String[] args){
    HashSet<String> line=new HashSet<>();//HashSet存放无序但不重复的数组
    HashSet<Integer> a = new HashSet<>();
    for(int i=0;i<20;i++){//i表示横坐标
        for(int j=0;j<21;j++){//j表示纵坐标
            a.add(i*100+j);//a/100=i;a%100=y;
        }
    }
    List<Integer> list=new ArrayList<>(a);//要想获取数组a中的数,就必须将数组a转成list类型进行获取
    for(int i=0;i<20*21;i++){//固定一个点,在其余点中寻找符合条件的点
        int x1=list.get(i)/100;//固定点x轴
        int y1=list.get(i)%100;//固定点y轴
        for(int j=i+1;j<20*21;j++){//固定点之后的所有点
            int x2=list.get(j)/100;
            int y2=list.get(j)%100;
            int x=x1-x2;//两点x轴差值
            int y=y1-y2;//两点y轴差值
            if(x==0){//斜率不存在(垂直x轴)
                String s=" "+x1;
                line.add(s);//加入该直线
            }
            else {
                int k=gcd(y,x);//求(y1-y2)/(x1-x2)最大公因数k(求得最简的K)
                y=y/k;//化简x,y
                x=x/k;
                int b1=y1*x-x1*y;//求y1(x1-x2)-x1(y1-y2)。由于y=kx+b(将k=(y1-y2)/(x1-x2)带入得)->b=(y1(x1-x2)-x1(y1-y2))/(x1-x2)
                int b2=x;//x1-x2
                int b=gcd(b1,b2);//求b=(y1(x1-x2)-x1(y1-y2))/(x1-x2)
                b1=b1/b;//化简b1,b2
                b2=b2/b;
                String s=y+" "+x+" "+b1+" "+b2;//将公式用字符串形式存入数组
                line.add(s);//去重
            }
        }
    }
    System.out.println(line.size());
}

static int gcd(int a,int b){//求a,b最大公因数,即求最简的K
    if(b==0)
        return a;
    return gcd(b,a%b);
}
答案:40257

思路:通过循环找到两个点,再通过递归找到这条直线的斜率和截距的最大公因数。最终得出这条直线的最简式并将其存入数组。所有点遍历完后,求得数组中不同直线的个数。

规律:找点-->求k-->求b-->存储。

注意:数字转字符串时一定要加" ",中间一定要有空格,否则会漏掉重复的。

2022年

给定一个只包含大写字母的字符串S,请你输出其中出现次数最多的字母。如果有多个字母出现了最多次,按字母表顺序依次输出所有这些字母。

public static void main(String[] args){
    Scanner input = new Scanner(System.in);
    char[] s=input.nextLine().toCharArray();//输入字符串并将其存为字符数组
    char[] count=new char[26];
    for(int i=0;i<s.length;i++){//对相同字母进行计数
        count[s[i]-'A']+=1;//这种写法值得学习
    }
    int max=count[0];
    String str="";
    for(int i=0;i<count.length;i++){//循环字母找最大值并以字符串形式存入str字串中
        if(count[i]>max){
            max=count[i];
            str=""+(char)(i+'A');
        }
        else if(count[i]==max){
            str+=(char)(i+'A');
        }
    }
    System.out.println(str);
}
输入BABBACAC,输出AB

思路:将输入的字符串以字符形式存储,以字符ASCLL码为下标对相同字母进行计数。循环所有字母找出数量最多的并以字符串形式输出。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值