【蓝桥杯】第九届JavaA组题解和技巧总结

1标题:分数

1/1 + 1/2 + 1/4 + 1/8 + 1/16 + …
每项是前一项的一半,如果一共有20项,
求这个和是多少,结果用分数表示出来。
类似:
3/2
当然,这只是加了前2项而已。分子分母要求互质。

注意:
需要提交的是已经约分过的分数,中间任何位置不能含有空格。
请不要填写任何多余的文字或符号。
思路
1.等比数列求和,基础数学知识要知道
2.结果用互质分数表示,考察最大公约数
3.java BigInteger的使用

import java.math.BigInteger;
import java.util.Scanner;

class Main
{	
	static long st,et;
	static Scanner sc=new Scanner(System.in);
	//全局变量

	public static void main(String[] args) 
	{	st =System.currentTimeMillis();
	//程序开始
		BigInteger two = BigInteger.valueOf(2);
		BigInteger a = two.pow(20).subtract(BigInteger.ONE);
		BigInteger b = two.pow(10);
		BigInteger gys= a.gcd(b);
		System.out.println(a.divide(gys)+"/"+b.divide(gys)); 
		
		
	//程序结束
	 et=System.currentTimeMillis();
	 System.out.println();System.out.println(et-st+"ms");
	}
}

补充
最大公约数的求法

 public static int test1(int a,int b){
        int max=a>b?a:b;
        int min=a<b?a:b;
        int c =max%min;
        if(c==0){
            return min;
        }
        return test1(c,min);
 public static int test2(int a,int b){
        int max=a>b?a:b;
        int min=a<b?a:b;
        int c=max-min;
        if(c==0){
            return min;
        }
        return test2(c,min);
    }

2标题:星期一

整个20世纪(1901年1月1日至2000年12月31日之间),一共有多少个星期一?
(不要告诉我你不知道今天是星期几)

注意:需要提交的只是一个整数,不要填写任何多余的内容或说明文字。
思路
计算天数,整除7
要知道闰年公式
注意在两个日期之间是包含这两天的,所以,1月1日到本年12月31日刚好是一年的时间

3标题:复数幂

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

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

注意:需要提交的是一个很庞大的复数,不要填写任何多余内容。
分析
复数乘法
题目中明确说了这个数很大需要掌握bigInteger

import java.math.BigInteger;
import java.util.Scanner;

class Main
{	
	static long st,et;
	static Scanner sc=new Scanner(System.in);
	//全局变量

	public static void main(String[] args) 
	{	st =System.currentTimeMillis();
	//程序开始
		BigInteger aa =null;
		BigInteger bb = null ;
		BigInteger a =BigInteger.valueOf(2);
		BigInteger b =BigInteger.valueOf(3);
		for (int i = 0; i < 3; i++) {
			 aa = a.multiply(BigInteger.valueOf(2)).subtract(b.multiply(BigInteger.valueOf(3)));
			 bb = a.multiply(BigInteger.valueOf(3)).add(b.multiply(BigInteger.valueOf(2)));
			 a=aa;
			 b=bb;
		}
		String sign = bb.compareTo(BigInteger.ZERO)<0?"-":"+";
		System.out.println(aa+sign+bb.abs()+"i");//注意绝对值
	//程序结束
	 et=System.currentTimeMillis();
	 System.out.println();System.out.println(et-st+"ms");
	}
}

4标题:方格计数

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

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

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

在这里插入图片描述分析
以圆心为原点,看第一象限,在第一象限,只要是方格最右上角的点在圆内,就满足条件,小方格最右上的点的坐标x,y 属于[1,1000],最后四个象限内的,就是第一象限的四倍。

import java.math.BigInteger;
import java.util.Scanner;

class Main
{	
	static long st,et;
	static Scanner sc=new Scanner(System.in);
	//全局变量

	public static void main(String[] args) 
	{	st =System.currentTimeMillis();
	//程序开始
	     int count =0 ;
	      for (int i = 1; i <=1000 ; i++) {
			for (int j = 1; j <=1000; j++) {
				if(i*i+j*j<=1000*1000)
					count++;
			}
		}System.out.println(4*count);
	//程序结束
	 et=System.currentTimeMillis();
	 System.out.println();System.out.println(et-st+"ms");
	}
}

5标题:打印图形

如下的程序会在控制台绘制分形图(就是整体与局部自相似的图形)。

当n=1,2,3的时候,输出如下:
请仔细分析程序,并填写划线部分缺少的代码。
在这里插入图片描述

源程序:

public class Main
{
	static void show(byte[][] buf){
		for(int i=0; i<buf.length; i++){
			for(int j=0; j<buf[i].length; j++){
				System.out.print(buf[i][j]==0? ' ' : 'o');
			}
			System.out.println();
		}
	}
	
	static void draw(byte[][] buf, int x, int y, int size){
		if(size==1){
			buf[y][x] = 1;
			return;
		}
		
		int n = ________________________ ;  // 填空
		draw(buf, x, y, n);
		draw(buf, x-n, y ,n);
		draw(buf, x+n, y ,n);
		draw(buf, x, y-n ,n);
		draw(buf, x, y+n ,n);
	}
	
	public static void main(String[] args){
		final int N = 3;
		int t = 1;
		for(int i=0; i<N; i++) t *= 3;
		
		byte[][] buf = new byte[t][t];
		draw(buf, t/2, t/2, t);
		show(buf);
	}
}

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

找规律题,最快速方法就是用简单的图形去实验,然后很容易得出
int n = size/3;

6标题:航班时间

【问题背景】
小h前往美国参加了蓝桥杯国际赛。小h的女朋友发现小h上午十点出发,上午十二点到达美国,于是感叹到“现在飞机飞得真快,两小时就能到美国了”。

小h对超音速飞行感到十分恐惧。仔细观察后发现飞机的起降时间都是当地时间。由于北京和美国东部有12小时时差,故飞机总共需要14小时的飞行时间。

不久后小h的女朋友去中东交换。小h并不知道中东与北京的时差。但是小h得到了女朋友来回航班的起降时间。小h想知道女朋友的航班飞行时间是多少。

【问题描述】
对于一个可能跨时区的航班,给定来回程的起降时间。假设飞机来回飞行时间相同,求飞机的飞行时间。

【输入格式】
从标准输入读入数据。

一个输入包含多组数据。

输入第一行为一个正整数T,表示输入数据组数。

每组数据包含两行,第一行为去程的 起降 时间,第二行为回程的 起降 时间。

起降时间的格式如下

h1:m1:s1 h2:m2:s2

h1:m1:s1 h3:m3:s3 (+1)

h1:m1:s1 h4:m4:s4 (+2)
表示该航班在当地时间h1时m1分s1秒起飞,

第一种格式表示在当地时间 当日 h2时m2分s2秒降落

第二种格式表示在当地时间 次日 h3时m3分s3秒降落。

第三种格式表示在当地时间 第三天 h4时m4分s4秒降落。

对于此题目中的所有以 hⓂ️s 形式给出的时间, 保证 ( 0<=h<=23, 0<=m,s<=59 ).

【输出格式】
输出到标准输出。

对于每一组数据输出一行一个时间hh:mm:ss,表示飞行时间为hh小时mm分ss秒。

注意,当时间为一位数时,要补齐前导零。如三小时四分五秒应写为03:04:05。

【样例输入】
3
17:48:19 21:57:24
11:05:18 15:14:23
17:21:07 00:31:46 (+1)
23:02:41 16:13:20 (+1)
10:19:19 20:41:24
22:19:04 16:41:09 (+1)

【样例输出】
04:09:05
12:10:39
14:22:05

【限制与约定】
保证输入时间合法,飞行时间不超过24小时。

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;

class Main
{	
	static long st,et;
	static Scanner sc=new Scanner(System.in);
	//全局变量
    
	//获取时间
	static long getTime(String c) throws ParseException
	{
		String[] split = c.split(" ");
		SimpleDateFormat format = new SimpleDateFormat("hh:mm:ss");//用日期格式分时间
		Date d1 = format.parse(split[0]);
		Date d2 = format.parse(split[1]);//如果记不得也可以分出时分秒,都以00:00:00为基础化成秒作差
		int day= split.length==3?Integer.parseInt(split[2].substring(2, 3)):0;
		return (d2.getTime()-d1.getTime())/1000 + day *3600*24;
	}
	public static void main(String[] args) throws ParseException 
	{	st =System.currentTimeMillis();
	//程序开始
		int n = sc.nextInt();
		sc.nextLine();//用nextline()一定要注意读取回车
		for (int i = 0; i < n;i++) {
			long s1 =getTime(sc.nextLine());//注意会读取空格
			long s2 =getTime(sc.nextLine());//注意会读取空格
			long s =(s1+s2)/2;
 			System.out.printf("%02d:%02d:%02d\n",s/3600,s/60%60,s%60);//0表示补充占位0,2表示两位数,获取时分秒很巧妙
		}
		
	//程序结束
	 et=System.currentTimeMillis();
	 System.out.println();System.out.println(et-st+"ms");
	}
	
}

7 标题:三体攻击

【题目描述】
三体人将对地球发起攻击。为了抵御攻击,地球人派出了 A × B × C 艘战舰,在太空中排成一个 A 层 B 行 C 列的立方体。其中,第 i 层第 j 行第 k 列的战舰(记为战舰 (i, j, k))的生命值为 d(i, j, k)。

三体人将会对地球发起 m 轮“立方体攻击”,每次攻击会对一个小立方体中的所有战舰都造成相同的伤害。具体地,第 t 轮攻击用 7 个参数 lat, rat, lbt, rbt, lct, rct, ht 描述;
所有满足 i ∈ [lat, rat],j ∈ [lbt, rbt],k ∈ [lct, rct] 的战舰 (i, j, k) 会受到 ht 的伤害。如果一个战舰累计受到的总伤害超过其防御力,那么这个战舰会爆炸。

地球指挥官希望你能告诉他,第一艘爆炸的战舰是在哪一轮攻击后爆炸的。

【输入格式】
从标准输入读入数据。
第一行包括 4 个正整数 A, B, C, m;
第二行包含 A × B × C 个整数,其中第 ((i − 1)×B + (j − 1)) × C + (k − 1)+1 个数为 d(i, j, k);
第 3 到第 m + 2 行中,第 (t − 2) 行包含 7 个正整数 lat, rat, lbt, rbt, lct, rct, ht。

【输出格式】
输出到标准输出。
输出第一个爆炸的战舰是在哪一轮攻击后爆炸的。保证一定存在这样的战舰。

【样例输入】
2 2 2 3
1 1 1 1 1 1 1 1
1 2 1 2 1 1 1
1 1 1 2 1 2 1
1 1 1 1 1 1 2

【样例输出】
2

【样例解释】
在第 2 轮攻击后,战舰 (1,1,1) 总共受到了 2 点伤害,超出其防御力导致爆炸。

【数据约定】
对于 10% 的数据,B = C = 1;
对于 20% 的数据,C = 1;
对于 40% 的数据,A × B × C, m ≤ 10, 000;
对于 70% 的数据,A, B, C ≤ 200;
对于所有数据,A × B × C ≤ 10^6, m ≤ 10^6, 0 ≤ d(i, j, k), ht ≤ 10^9。

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 3000ms
分析
这个题目读完之后就应该能发现可以用暴力解法解决,看数据约定,70%的数据在200以内,所以用暴力法能得到大部分的分数,如果有能力可以去考虑优化的算法,但是考试中这道题的暴力法还是性价比比较高的方式.
需要注意的点就是多维数组的线性表示方法.

import java.util.Scanner;

class Main
{	
	static long st,et;
	static Scanner sc=new Scanner(System.in);
	//全局变量static
	static int[][][] zj;
	public static void main(String[] args) 
	{	st =System.currentTimeMillis();
	//程序开始
		int a=sc.nextInt();
		int b=sc.nextInt();
		int c=sc.nextInt();
		int m=sc.nextInt();
		zj=new int[a][b][c];
		int[][] hit =new int[m][7];
		for (int i = 0; i < a; i++) {
			for (int j = 0; j < b; j++) {
				for (int j2 = 0; j2 < c; j2++) {
					zj[i][j][j2]=sc.nextInt();
				}
			}
		}
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < 7; j++) {
				hit[i][j]=sc.nextInt();
			}
				for (int j2 = hit[i][0]-1; j2 < hit[i][1]; j2++) 
					for (int j3 = hit[i][2]-1; j3 < hit[i][3]; j3++) 
						for (int j4 = hit[i][4]-1; j4 < hit[i][5]; j4++) 
						{
							zj[j2][j3][j4]-=hit[i][6];
							if(zj[j2][j3][j4]<0) {
								System.out.println(i+1);
								return;
							}
						}
				
			
		}
		
	//程序结束
	 et=System.currentTimeMillis();
	 System.out.println();System.out.println(et-st+"ms");
	}
}

8标题:全球变暖

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


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

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

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

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





…#…

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

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

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

【输出格式】
一个整数表示答案。

【输入样例】

【输出样例】
1
分析
就是dfs和bfs搜索,然后搜索的过程中计数,设置访问数组,是否沉没数组,防止重复访问, 这个题目,显然用bfs,dfs会产生栈的泄露

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


class Main
{	
	static long st,et;
	static Scanner sc=new Scanner(System.in);
	//全局变量static
	static char[][]land;
	static int[][] mark;
	static int[][] down;
	static int res=0;
	static int next[][]= {{1,0},{0,1},{-1,0},{0,-1}};//逆时针
	static int n;
	static int num;
	static int sink;
	//内部静态类
	static class point
	{
		int x,y;
		point(int a,int b){
			x=a;y=b;
		}
	}
	//静态方法
	static int dfs(int x,int y)
	{	
		for (int i = 0; i < 4; i++) {
			int nx=x+next[i][0];
			int ny=y+next[i][1];
			if(nx>=0&&nx<n&&ny>=0&&ny<n)
			{	
				
				if(mark[nx][ny]==0&&land[nx][ny]=='#')
				{	
					mark[nx][ny]=1;
					num++;
					dfs(nx,ny);
				}
				if(land[nx][ny]=='.'&&down[x][y]==0)
				{
					down[x][y]=1;
					sink++;
				}
					
			}
		}
		//System.out.println(num+","+sink);
		return num==sink?1:0;
	}
	
	static int bfs(int x,int y)
	{
		Queue<point> qu=new LinkedList<point>();
		qu.offer(new point(x, y));
		while(!qu.isEmpty())
		{
			point coor=qu.poll();
			for (int i = 0; i < 4; i++) {
				int nx=coor.x+next[i][0];
				int ny=coor.y+next[i][1];
				if(nx>=0&&nx<n&&ny>=0&&ny<n)
				{	
					if(mark[nx][ny]==0&&land[nx][ny]=='#')
					{	
						mark[nx][ny]=1 ;
						qu.offer(new point(nx, ny));
						//System.out.println(nx+","+ny);
						num++;
						
					}
					if(land[nx][ny]=='.'&&down[coor.x][coor.y]==0)
					{
						down[coor.x][coor.y]=1;
						sink++;
					}
				}
			}
		}
		//System.out.println(num+""+sink);
		return num==sink?1:0;
	}
	public static void main(String[] args) 
	{	st =System.currentTimeMillis();
	//程序开始
		n=sc.nextInt();
		land =new char[n][n];
		mark =new int[n][n];
		down =new int[n][n];
		for (int i = 0; i < n; i++) {
			land[i]=sc.next().toCharArray();
		}
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				if(land[i][j]=='#'&&mark[i][j]==0) {
					mark[i][j]=1;num=1;sink=0;
					int k =bfs(i,j);
					res+=k;
				}
			}
		}
		System.out.println(res);
	//程序结束
	 et=System.currentTimeMillis();
	 System.out.println();System.out.println(et-st+"ms");
	}
}

9标题:倍数问题

【题目描述】
众所周知,小葱同学擅长计算,尤其擅长计算一个数是否是另外一个数的倍数。但小葱只擅长两个数的情况,当有很多个数之后就会比较苦恼。现在小葱给了你 n 个数,希望你从这 n 个数中找到三个数,使得这三个数的和是 K 的倍数,且这个和最大。数据保证一定有解。

【输入格式】
从标准输入读入数据。
第一行包括 2 个正整数 n, K。
第二行 n 个正整数,代表给定的 n 个数。

【输出格式】
输出到标准输出。
输出一行一个整数代表所求的和。

【样例输入】
4 3
1 2 3 4

【样例输出】
9

【样例解释】
选择2、3、4。

【数据约定】
对于 30% 的数据,n <= 100。
对于 60% 的数据,n <= 1000。
对于另外 20% 的数据,K <= 10。
对于 100% 的数据,1 <= n <= 10^5, 1 <= K <= 10^3,给定的 n 个数均不超过 10^8。

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
分析
可以暴力破解,但是可以考虑化简层数和每层循环的数量,三个数和的模k为0,确定两个数,最后一个就可以确定,最后一个%k的值是+前两个的%k的值是k的倍数,考虑找最大的,则可以将每个数按照余数分类,然后只去最大的前三个数,
然后按照前两个数的余数的值遍历,就是在分组有放回的取两个

import java.util.Scanner;

class Main
{	
	static long st,et;
	static Scanner sc=new Scanner(System.in);
	//全局变量static

	public static void main(String[] args) 
	{	st =System.currentTimeMillis();
	//程序开始
		int n=sc.nextInt();
		int k=sc.nextInt(); 
		int[][] group =new int[k][3];
		for (int i = 0; i < n; i++) {
			int num = sc.nextInt();
			int re= num%k;
			if(num>group[re][0])
			{
				group[re][2]=group[re][1];group[re][1]=group[re][0];group[re][0]=num;
			}
			else if(num>group[re][1])
			{
				group[re][2]=group[re][1];group[re][1]=num;
			}
			else {
				group[re][2]=Math.max(group[re][2], num);
			}
		}
		int res=0;
		for (int i = 0; i < k; i++) {
			for (int j = i; j < k; j++) {
				int j2 = (k+k-i-j)%k;
				int v1=group[i][0];
				int v2=0,v3=0;
				if(i==j)
				{
					v2=group[j][1];
					v3=j2==j?group[j2][2]:group[j2][0];
				}
				else {
					v2=group[j][0];
					v3=j2==i||j2==j?group[j2][1]:group[j2][0];
				}
				res=Math.max(res, v1+v2+v3);
			}
		}
		System.out.println(res);
	//程序结束
	 et=System.currentTimeMillis();
	 System.out.println();System.out.println(et-st+"ms");
	}
}

10标题:付账问题

【题目描述】
几个人一起出去吃饭是常有的事。但在结帐的时候,常常会出现一些争执。

现在有 n 个人出去吃饭,他们总共消费了 S 元。其中第 i 个人带了 ai 元。幸运的是,所有人带的钱的总数是足够付账的,但现在问题来了:每个人分别要出多少钱呢?

为了公平起见,我们希望在总付钱量恰好为 S 的前提下,最后每个人付的钱的标准差最小。这里我们约定,每个人支付的钱数可以是任意非负实数,即可以不是1分钱的整数倍。你需要输出最小的标准差是多少。

标准差的介绍:标准差是多个数与它们平均数差值的平方平均数,一般用于刻画这些数之间的“偏差有多大”。形式化地说,设第 i 个人付的钱为 bi 元,那么标准差为 : [参见p1.png]

【输入格式】
从标准输入读入数据。
第一行包含两个整数 n、S;
第二行包含 n 个非负整数 a1, …, an。

【输出格式】
输出到标准输出。
输出最小的标准差,四舍五入保留 4 位小数。
保证正确答案在加上或减去 10^−9 后不会导致四舍五入的结果发生变化。

【样例输入】
5 2333
666 666 666 666 666

【样例输出】
0.0000

【样例解释】
每个人都出 2333/5 元,标准差为 0。

再比如:
【样例输入】
10 30
2 1 4 7 4 8 3 6 4 7

【样例输出】
0.7928

【数据约定】
对于 10% 的数据,所有 ai 相等;
对于 30% 的数据,所有非 0 的 ai 相等;
对于 60% 的数据,n ≤ 1000;
对于 80% 的数据,n ≤ 10^5;
对于所有数据,n ≤ 5 × 10^5, 0 ≤ ai ≤ 10^9。
分析
首先平均值是固定的,要想每个人付钱的方差最小,那么就需要每个人付的钱越接近平均值越好,身上钱比平均值低的人,肯定要全付清。然后大于平均值的人要来弥补前面的人少付的,于是问题转换成,后面的人,在新的总金额下的方差最小问题,这样一来直到,最后一个子问题所有人都高于该子问题的平均值,子问题划分结束,这是一个典型的贪心算法。

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

class Main
{	
	static long st,et;
	static Scanner sc=new Scanner(System.in);
	//全局变量static

	public static void main(String[] args) 
	{	st =System.currentTimeMillis();
	//程序开始
		int n = sc.nextInt();
		double s = sc.nextInt();
		int[] m=new int[n];
		for (int i = 0; i < n; i++) {
			m[i]=sc.nextInt();
		}
		Arrays.sort(m);
		double fc=0;
		double avg=s*1.0/n;
		for (int i = 0; i < n; i++) {
			if(m[i]>=s*1.0/(n-i))
			{
				fc+= (n-i)*Math.pow(s*1.0/(n-i)-avg,2);
				break;
			}
			s-=m[i];
			fc+=Math.pow(m[i]-avg,2);
		}
		System.out.printf("%.4f",Math.sqrt(fc/n));
	//程序结束
	 et=System.currentTimeMillis();
	 System.out.println();System.out.println(et-st+"ms");
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值