2018年第九届蓝桥杯真题解析JavaB组

大佬轻喷,这篇题解有好几题都是看别人题解写出来的,我都标注了原作者的博客地址。一开始确实没想出来怎么做,还是太菜了,很多题写不来以至于在写得时候我会想,这篇题解的意义是什么呢?想了会我觉得是这样的:加深自己的印象,亲自把别人的想法敲出来这样更容易理解。还有就是把自己认为写的比较好的,容易理解的题解找出来,方便回顾,帮你们自己省时间,下次就不用再慢慢找;

相关题目:

2016年第七届蓝桥杯真题解析JavaB组

2016年第七届蓝桥杯真题解析JavaC组

2017年第八届蓝桥杯真题解析JavaB组

2017年第八届蓝桥杯真题解析JavaC组

2018年第九届蓝桥杯真题解析JavaC组

2019年第十届蓝桥杯真题解析JavaB组

2019年第十届蓝桥杯真题解析JavaC组

A:第几天

2000年的1月1日,是那一年的第1天。
那么,2000年的5月4日,是那一年的第几天?

思路:

判断2000年是否为闰年:
普通闰年:公历年份是4的倍数的,且不是100的倍数,为普通闰年。
(如20042020年就是闰年);
世纪闰年:公历年份是整百数的,必须是400的倍数才是世纪闰年
(如1900年不是世纪闰年,2000年是世纪闰年);
闰年共有366天(1-12月分别为31天;
29天,31天,30天,31天,30天,31天,31天,30天,31天,30天,
31天);
2000年是闰年,因此答案125

答案:125

B:方格计数

如图p1.png所示,在二维平面上有无数个1x1的小方格。

我们以某个小方格的一个顶点为圆心画一个半径为1000的圆。
你能计算出这个圆里有多少个完整的小方格吗?

注意:需要提交的是一个整数,不要填写任何多余内容。
在这里插入图片描述
思路:

拿右上半边距离,要判断一个方格是否在圆内,就要看这个方格的
右顶点离圆心的距离是否大于R,即i*i+j*j<=R*R,算出左半边后乘4
就是最后答案;

代码:

package JB2018;

public class 方格计数B {
    public static void main(String[] args) {
        int ans=0;
        for(int i=1;i<=1000;i++) {
            for(int j=1;j<=1000;j++) {
                if(i*i+j*j<=1000000) {
                    ans++;

                }
            }
        }
        System.out.println(ans*4);

    }
}

答案:3137548

C:复数幂

设i为虚数单位。对于任意正整数n,(2+3i)^n 的实部和虚部都是整数。
求 (2+3i)^123456 等于多少? 即(2+3i)的123456次幂,这个数字很大,要求精确表示。

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

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

思路:

以前没用过BigInteger,丝毫不晓得怎么用,看了一篇大佬的题解,
觉得很好我就不在关公面前耍大刀了,链接放这了

第九届蓝桥杯省赛–复数幂

代码:

 1 import java.math.BigInteger;
 2 
 3 public class ComplexPower {
 4 
 5     public static void main(String[] args) {
 6         BigInteger bigA = new BigInteger("2");
 7         BigInteger bigB = new BigInteger("3");
 8         BigInteger bigC = new BigInteger("2");
 9         BigInteger bigD = new BigInteger("3");
10         System.out.println(f(bigA,bigB,bigC,bigD));
11     }
12     
13     public static String f(BigInteger bigA, BigInteger bigB, BigInteger bigC, BigInteger bigD) {
14         int count = 1;
15         BigInteger sb = new BigInteger("0");
16         BigInteger xb = new BigInteger("0");
17         while(count<123456) {
18              sb = (bigA.multiply(bigC).subtract(bigB.multiply(bigD))) ;
19              xb = (bigB.multiply(bigC).add(bigA.multiply(bigD)));
20             bigC = sb;
21             bigD = xb;
22             count++;
23         }
24         return  sb  +""+ xb +"i"; //不用加字符串“+”、"-",因为运算本身自带符号
25     }
26 }


D:测试次数

x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。
各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。

x星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的2楼。

如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数=7。
特别地,如果手机从第1层扔下去就坏了,则耐摔指数=0。
如果到了塔的最高层第n层扔没摔坏,则耐摔指数=n

为了减少测试次数,从每个厂家抽样3部手机参加测试。

某次测试的塔高为1000层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?

请填写这个最多测试次数。

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

说实话我实在没想到填空题这么难,这可能就是太菜了吧,
这里有一题有视频讲解y总的,这题大佬写的答案和y总的
视频教程链接放下面了:

鸡蛋的硬度——yxc

测试次数

E:快速排序

以下代码可以从数组a[]中找出第k小的元素。

它使用了类似快速排序中的分治算法,期望时间复杂度是O(N)的。

请仔细阅读分析源码,填写划线部分缺失的内容。

import java.util.Random;
public class Main{
	public static int quickSelect(int a[], int l, int r, int k) {
		Random rand = new Random();
		int p = rand.nextInt(r - l + 1) + l;
		int x = a[p];
		int tmp = a[p]; a[p] = a[r]; a[r] = tmp;
		int i = l, j = r;
		while(i < j) {
                	while(i < j && a[i] < x) i++;
                	if(i < j) {
                        	a[j] = a[i];
                        	j--;
                	}
                	while(i < j && a[j] > x) j--;
                	if(i < j) {
                        	a[i] = a[j];
                        	i++;
                	}
        	}
        	a[i] = x;
        	p = i;
        	if(i - l + 1 == k) return a[i];
        	if(i - l + 1 < k) return quickSelect( _________________________________ ); //填空
        	else return quickSelect(a, l, i - 1, k);	
	}
	public static void main(String args[]) {
		int [] a = {1, 4, 2, 8, 5, 7};
		System.out.println(quickSelect(a, 0, 5, 4));
	}
}

注意:只提交划线部分缺少的代码,不要抄写任何已经存在的代码或符号。

思路:

Math.random()来随机选择[0,1)内的任意数,如果需要挑出[5,99]
闭区间的任意整数,则可以这样设置
        int num = 5 + rand.nextInt(99 + 1 - 5);
然后看一下别人的把,我太菜了,没想出来

(第九届)第五题-快速排序

答案:a, i+1, r, r-(i-l+1)

F:递增三元组

给定三个整数数组
A = [A1, A2, … AN],
B = [B1, B2, … BN],
C = [C1, C2, … CN],
请你统计有多少个三元组(i, j, k) 满足:

  1. 1 <= i, j, k <= N
  2. Ai < Bj < Ck

【输入格式】
第一行包含一个整数N。
第二行包含N个整数A1, A2, … AN。
第三行包含N个整数B1, B2, … BN。
第四行包含N个整数C1, C2, … CN。

对于30%的数据,1 <= N <= 100
对于60%的数据,1 <= N <= 1000
对于100%的数据,1 <= N <= 100000 0 <= Ai, Bi, Ci <= 100000

【输出格式】

一个整数表示答案

【输入样例】

3
1 1 1
2 2 2
3 3 3

【输出样例】

27

思路:

1.这题暴力可以得30%的分数,要优化,这里用的是二分法,先全部排序
然后我们以B数组为基准,用二分在A数组中找第一个大于灯B[i]的数字下
标m,同理在C数组找第一个小于等于B[i]的数字下标n,然后
(m-1)*(B.length-n)就是B[i]这个点的所有满足的条件的三元组个数;

2.在用分的时候,下标的左右边界分别要是(0,n+1)因为有可能存在找不
到的情况,举个例子:A[]={3,3,3},B[1]=2,用二分的时候找不到,此时
left应该是等于零的,如果用边界是(1,n)就会有歧义

代码:

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

public class Main {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();
        int N=100010;
        int a[]=new int[N];
        int b[]=new int[N];
        int c[]=new int[N];
        for(int i=1;i<=n;i++){
            a[i]=input.nextInt();
        }
        for(int i=1;i<=n;i++){
            b[i]=input.nextInt();
        }
        for(int i=1;i<=n;i++){
            c[i]=input.nextInt();
        }
        Arrays.sort(a,1,n+1);
        Arrays.sort(b,1,n+1);
        Arrays.sort(c,1,n+1);
        long res=0;
        for(int i=1;i<=n;i++){
          
            //这样它之前的所有数都比b[i]小,用二分法
            int left=0;
            int right=n+1;
            int mid=0;
            while(left<right){
              mid=(left+right)/2; 
              if(a[mid]>=b[i]){
              right=mid;
              }
              else
              {
                  left=mid+1;
              }
            }
              //在c找最小的比b[i]大的值的下标
              int left2=0;
              int right2=n+1;
              while(left2<right2){
                   mid=(left2+right2+1)/2;
                   if(c[mid]<=b[i]){
                       left2=mid;
                   }
                   else{
                       right2=mid-1;
                   }
              }
              if(left==0||left2==n+1)
              continue;
              else{
                 res+=((long)(left-1)*(n-left2)); 
              }
            
        }
        System.out.println(res);
    }
}

G:螺旋折线

如图p1.pgn所示的螺旋折线经过平面上所有整点恰好一次。
对于整点(X, Y),我们定义它到原点的距离dis(X, Y)是从原点到(X, Y)的螺旋折线段的长度。

例如dis(0, 1)=3, dis(-2, -1)=9

给出整点坐标(X, Y),你能计算出dis(X, Y)吗?
在这里插入图片描述

【输入格式】
X和Y

对于40%的数据,-1000 <= X, Y <= 1000
对于70%的数据,-100000 <= X, Y <= 100000
对于100%的数据, -1000000000 <= X, Y <= 1000000000

【输出格式】
输出dis(X, Y)

【输入样例】
0 1

【输出样例】
3

在这里插入图片描述
思路:

1.把图转换一下,就可以看出来里面的正方形的周长是公差为8的
等差数列,我们先把要求点的里面的所有正方形周长之和,再求
该点与这个点所在的正方形的左下角的距离,两者相加就是答案;

2.为什么是左下角,因为旋转之后原来的那个点变成左下角那个点,
算目标点与左下角那个点的距离,不能直接算要判断情况,因为为
变换之前图形是顺时针圈扩展的,我们算的时候也要按逆时针
“顺时针”算;

3.顺时针算到其所在正方形的左下角有两种情况,x<=y,和x>y两种,
第一种的情况是直接减去(-N,-N)这个坐标就行了,这个距离最短,
第二种是距离比较长的,正方形周长减去该点用第一种方法算的距离;
package JB2018;

import java.util.Scanner;

public class 螺旋折线 {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int x=input.nextInt();
        int y=input.nextInt();
        int N=Math.max(Math.abs(x),Math.abs(y));//这个点所在第几个正方形
        //前n-1个正方形的周长,根据等差数列前n项和变形得
        int sum=4*N*(N-1);
        //算该点与所在正方形左下角的距离
        //左小角的坐标(-N,-N)
        if(x<=y){//根据折叠规律,可得出当x<=y的时候直接减就好了
            sum+=(x-(-N))+y-(-N);

        }
        else //拿周长减去 直接减所得的距离就是 最终的距离

        {
            sum+=(8*N-((x-(-N))+y-(-N)));
        }
        System.out.println(sum);
    }
}

思路来源:zzzmj_

H:日志统计

小明维护着一个程序员论坛。现在他收集了一份"点赞"日志,日志共有N行。其中每一行的格式是:

ts id

表示在ts时刻编号id的帖子收到一个"赞"。

现在小明想统计有哪些帖子曾经是"热帖"。如果一个帖子曾在任意一个长度为D的时间段内收到不少于K个赞,小明就认为这个帖子曾是"热帖"。

具体来说,如果存在某个时刻T满足该帖在[T, T+D)这段时间内(注意是左闭右开区间)收到不少于K个赞,该帖就曾是"热帖"。

给定日志,请你帮助小明统计出所有曾是"热帖"的帖子编号。

【输入格式】
第一行包含三个整数N、D和K。
以下N行每行一条日志,包含两个整数ts和id。

对于50%的数据,1 <= K <= N <= 1000
对于100%的数据,1 <= K <= N <= 100000 0 <= ts <= 100000 0 <= id <= 100000

【输出格式】
按从小到大的顺序输出热帖id。每个id一行。

【输入样例】
7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3

【输出样例】
1
3

思路:

1.我们要判断一个帖子是不是热帖,就要知道它在某个
区间内是否点赞数大于等于K,而且这个区间还要有序才
能保证答答案的正确性,这就要把时间与对应的id,一
起排序,需要定义一个类,然后用ArrayList.sort去
排序;
class Ps implements Comparable<Ps>{
    public int t;
    public int id;

    public Ps(int t,int id){
        this.t=t;
        this.id=id;

    }
    public int compareTo(Ps o){
        return Integer.compare(t,o.t);
    }
}

2.排好序后我们就在双指针加滑动窗口在规定的区间
里找,不能两重循环暴力找会超时,只能过百分之五
十的数据;

3.用j,i分别表示窗口的左右边界,每次遍历的时候
hot[ps[i].id]++;
当ps[i].t-ps[j].t>=D的时候窗口就要缩小,还要
把左边界所指的那个时间的对应的店铺热度减掉,即
hot[ps[j].id]--;

4.经过上述操作后如果当前时间点对应的店铺的热度
大于等于K,则表示这个店铺是热帖;

代码

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

public class Main {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int N=input.nextInt();
        int D=input.nextInt();
        int K=input.nextInt();
        Ps[] logs = new Ps[N+1];
        int ans[]=new int[1000000];
        int hot[]=new int[1000000];
        for(int i=0;i<N;i++){
            int t=input.nextInt();
            int id=input.nextInt();
            logs[i] = new Ps(t,id);
        }
        Arrays.sort(logs,0,N);
        for(int i=0,j=0;i<N;i++){
            hot[logs[i].id]++;
            while(logs[i].t-logs[j].t>=D){
                hot[logs[j].id]--;
                j++;
            }
            if(hot[logs[i].id]>=K){
                ans[logs[i].id]=1;
            }
        }
        for(int i=0;i<1000000;i++){
            if(ans[i]==1)
                System.out.println(i);
        }

    }

}

class Ps implements Comparable<Ps>{
    public int t;
    public int id;

    public Ps(int t,int id){
        this.t=t;
        this.id=id;

    }
    public int compareTo(Ps o){
        return Integer.compare(t,o.t);
    }
}

I:全球变暖

你有一张某海域NxN像素的照片,".“表示海洋、”#"表示陆地,如下所示:


.##…
.##…
…##.
…####.
…###.

其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有2座岛屿。

由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。

例如上图中的海域未来会变成如下样子:

.......
.......
.......
.......
....#..
.......
.......

请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。

【输入格式】

第一行包含一个整数N。 (1 <= N <= 1000)
以下N行N列代表一张海域照片。

照片保证第1行、第1列、第N行、第N列的像素都是海洋。

【输出格式】

一个整数表示答案。

【输入样例】

7 
.......
.##....
.##....
....##.
..####.
...###.
.......  

【输出样例】

1  
1.用BFS找到所有大岛屿的下标并标记下边,记录所有大岛屿的个数用
countsum记录下来;

2.在块大岛屿中找是否存在一个小岛屿四面不环海,如果有用count记
录下来;

3.countsum-count就是最后答案;


import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {
    public static int xx[]={0,-1,1,0,0};
    public static int yy[]={0,0,0,-1,1};
    static  int count=0;
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int N=input.nextInt();
        String []arr=new String[N];
        char [][]map=new char[N][N];
        for(int i=0;i<N;i++){
            arr[i]=input.next();
            map[i]=arr[i].toCharArray();
        }
      
        int [][]visited=new int[N][N];
        int countsum=0;
        for(int i=0;i<N;i++){
            for(int j=0;j<N;j++){
                if(visited[i][j]==0&&map[i][j]=='#') {
                    BFS(map, visited, i, j, N);
                    countsum++;
                }
            }
        }

        System.out.println(countsum-count);
    }
    public static void BFS(char [][]map,int [][]visited,int X,int Y,int N){
        Queue<Integer> heng=new LinkedList<Integer>();
        Queue<Integer> zong=new LinkedList<Integer>();
        int startx=X;
        int starty=Y;
        visited[startx][starty]=1;
        heng.offer(startx);
        zong.offer(starty);
        int isexist=0;//判断同一块岛屿中是否已经存在一个小岛屿四面不环海
        while (!heng.isEmpty()){
            int nowx=heng.poll();
            int nowy=zong.poll();
            //四个方向
            for(int i=1;i<=4;i++){
                int fowardx=nowx+xx[i];
                int fowardy=nowy+yy[i];
                if(fowardx<0||fowardx>=N)
                    continue;
                else if(fowardy<0||fowardy>=N)
                    continue;
                else if(visited[fowardx][fowardy]!=0)
                    continue;
                else if(map[fowardx][fowardy]!='#')
                    continue;

                    heng.offer(fowardx);
                    zong.offer(fowardy);
                    visited[fowardx][fowardy] = 1;
                    //之前是否已经有过包围的点,若没有看看这个点是否被海水包围
                    if (isexist == 0) {
                        int flag = 0;
                        for (int k = 1; k <= 4; k++) {
                            if (map[fowardx + xx[k]][fowardy + yy[k]] == '.') {
                                flag = 1;
                                break;
                            }
                        }
                        //说明没有被海水包围
                        if (flag == 0) {
                            count++;
                            isexist++;
                        }
                    }

            }


        }

    }
}

标题:堆的计数

我们知道包含N个元素的堆可以看成是一棵包含N个节点的完全二叉树。
每个节点有一个权值。对于小根堆来说,父节点的权值一定小于其子节点的权值。

假设N个节点的权值分别是1~N,你能求出一共有多少种不同的小根堆吗?

例如对于N=4有如下3种:

在这里插入图片描述

由于数量可能超过整型范围,你只需要输出结果除以1000000009的余数。

【输入格式】

一个整数N。

对于40%的数据,1 <= N <= 1000
对于70%的数据,1 <= N <= 10000
对于100%的数据,1 <= N <= 100000

【输出格式】

一个整数表示答案。

【输入样例】

4

【输出样例】

3

这题不适合我这个菜鸡,写不来看不懂

©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页