2018年 第9届 蓝桥杯 Java B组 省赛真题详解及总结


  • 注意:部分代码及程序 源自 蓝桥杯 官网视频(历年真题解析) 郑未老师
  1. 2013年 第04届 蓝桥杯 Java B组 省赛真题详解及小结
  2. 2014年 第05届 蓝桥杯 Java B组 省赛真题详解及小结
  3. 2015年 第06届 蓝桥杯 Java B组 省赛真题详解及小结
  4. 2016年 第07届 蓝桥杯 Java B组 省赛真题详解及小结
  5. 2017年 第08届 蓝桥杯 Java B组 省赛真题详解及小结
  6. 2018年 第09届 蓝桥杯 Java B组 省赛真题详解及小结
  7. 2019年 第10届 蓝桥杯 Java B组 省赛真题详解及小结
  8. 2020年 第11届 蓝桥杯 Java B组 第1次模拟赛真题详解及小结(校内模拟)
  9. 2020年 第11届 蓝桥杯 Java B组 第2次模拟赛真题详解及小结
  10. 2020年 第11届 蓝桥杯 C/C++ B组 省赛真题详解及小结【第1场省赛 2020.7.5】【Java版】
  11. 2020年 第11届 蓝桥杯 Java B组 省赛真题详解及小结【第1场省赛 2020.7.5】
  12. 2020年 第11届 蓝桥杯 Java C组 省赛真题详解及小结【第1场省赛 2020.7.5】

目   录

一、第几天

二、方格计数

三、复数幂

测试

测试——输出到文件

解法一

解法二

四、测试次数

解法一

解法二

五、快速排序

六、递增三元组

解法一

解法二

七、螺旋折线

八、日志统计

九、全球变暖

十、堆的计数

小结

竞赛大纲

竞赛大纲A01_有n个孩子站成一圈

竞赛大纲A02_信用卡号验证

竞赛大纲A03_砝码称重

竞赛大纲A03_砝码称重2

竞赛大纲A03_砝码称重3


 

一、第几天

标题:第几天

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


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

【答案】:125

【解析】:31 + 29 + 31 + 30 + 4

二、方格计数

标题:方格计数

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

p1.png


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

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

【答案】:3137548

package provincialGames_09_2018;

public class A02_方格计数 {

	public static void main(String[] args) {

		// lwx解法
		int count = 0;
		for (int x = 0; x <= 1000; x++) {
			for (int y = 0; y <= 1000; y++) {
				if ((x + 1) * (x + 1) + (y + 1) * (y + 1) <= 1000 * 1000) {
					count++;
				}
			}
		}
		System.out.println(count * 4);

		// 郑未老师 解法1
		int r = 0;
		for (int i = -1000; i <= 1000; i++) {
			for (int j = -1000; j <= 1000; j++) {
				if (i * i + j * j <= 1000 * 1000) {
					if (i == 0 || j == 0) // 点不能在轴上
						continue;
					r++;
				}
			}
		}
		System.out.println(r);

		// 郑未老师 解法2【稍微优化一点的解法】
		int N = 1000;
		int y = N;
		int ans = 0;
		for (int x = 1; x <= N; x++) { //扫描每一行
			while (x * x + y * y > N * N && y > 0) {
				y--;
			}
			ans += y;
		}
		System.out.println(ans * 4);

	}

}

三、复数幂

标题:复数幂

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

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


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

【答案】:将答案输出到文件,文件大小为135KB,此处不再叙述。

b>0?"+":""

2次幂:循环一次
123456次幂:123455
//x = x*a - y*b;
//y = t*b + y*a;

测试

package provincialGames_09_2018;

import java.math.BigInteger;

public class A03_复数幂 {

	public static void main(String[] args) {
		BigInteger a = new BigInteger("2");
		BigInteger b = new BigInteger("3");
		BigInteger x = new BigInteger("2");
		BigInteger y = new BigInteger("3");
		for(int i = 0; i < 123455; i++) {
			BigInteger t = x;
			x = x.multiply(a).subtract(y.multiply(b));
			y = t.multiply(b).add(y.multiply(a));
		}
		System.out.println(x + "" + ((y.compareTo(BigInteger.ZERO) > 0)? "+" : "") + y + "i");
	}

}

测试——输出到文件

package provincialGames_09_2018;

import java.io.FileOutputStream;
import java.io.PrintStream;

public class A03_PrintStream {  //public class Redirectout

	public static void main(String[] args) {
		try {
			//一次性创建PrintStream输出流
			PrintStream ps = new PrintStream(new FileOutputStream("G:\\OUT.txt"));
			{
				//将标准输出重定向到ps输出流
				System.setOut(ps);
				//向标准输出输出一个字符串
				System.out.println("普通字符串");
				//向标准输出输出一个对象 System.out.println(new Redirectout());				
				System.out.println(new A03_PrintStream());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
/**
运行上面的程序将看不到任何输出---这意味着标准输出不再输出到屏幕,
而是输出到OUT.txt文件


System类里提供了如下三个重定向标准输入/输出的方法:
1.static void setErr(PrintStream err):重定向“标准”错误输出流
2.static void setIn(InputStream in):重定向“标准”输入流
3.static void setOut(PrintStream out):重定向“标准”输出流
*/

解法一

package provincialGames_09_2018;

//import java.io.*;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.math.BigInteger;

public class A03_复数幂2 {

	public static void main(String[] args) {
		try {
			//改变输出流,输出到work.txt文件
			PrintStream ps = new PrintStream(new FileOutputStream("G:\\work.txt"));
	        System.setOut(ps);  //文件输出  用System.out.println()即可将内容输出到文件中
			BigInteger a = new BigInteger("2");
			BigInteger b = new BigInteger("3");
			BigInteger x = new BigInteger("2");
			BigInteger y = new BigInteger("3");
			for(int i = 0; i < 123455; i++) {
				BigInteger t = x;
				x = x.multiply(a).subtract(y.multiply(b));
				y = t.multiply(b).add(y.multiply(a));
			}
			System.out.println(x + "" + ((y.compareTo(BigInteger.ZERO) > 0)? "+" : "") + y + "i");
		} catch (Exception e) {  //抛出异常
			e.printStackTrace();
		}
		
	}

}

解法二

package provincialGames_09_2018;

import java.io.File;
import java.io.PrintStream;
import java.math.BigInteger;

public class A03_复数幂3 {

	public static void main(String[] args) throws Exception {
		BigInteger two = BigInteger.valueOf(2);
		BigInteger three = BigInteger.valueOf(3);

		BigInteger a = BigInteger.valueOf(2);
		BigInteger b = BigInteger.valueOf(3);
		BigInteger aa = null;
		BigInteger bb = null;
		for (int i = 0; i < 123455; i++) {
			aa = a.multiply(two).subtract(b.multiply(three));// a*2-(b*3)
			bb = a.multiply(three).add(b.multiply(two));
			a = aa;
			b = bb;
		}
		System.setOut(new PrintStream(new File("D:\\out.txt")));
		System.out.println(aa + (bb.compareTo(BigInteger.ZERO) > 0 ? "-" : "+") + bb + "i");
	}

}

四、测试次数

标题:测试次数

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

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

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

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

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

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

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

【答案】:19

解法一

package provincialGames_09_2018;

public class A04_测试次数 { // 19

	public static void main(String[] args) {

		int[][] d = new int[1001][4]; // 有j个鸡蛋测试i层楼需要扔几次
		for (int i = 1; i <= 1000; i++) {
			d[i][1] = i; // 1个鸡蛋扔i次可以测试i层楼
		}
		for (int i = 1; i <= 1000; i++) {
			int min = Integer.MAX_VALUE;
			for (int j = 1; j <= i; j++) {
				min = Math.min(min, Math.max(j, d[i - j][2] + 1));
			}
			d[i][2] = min;
		}
		for (int i = 1; i <= 1000; i++) {
			int min = Integer.MAX_VALUE;
			for (int j = 1; j <= i; j++) {
				min = Math.min(min, Math.max(d[j - 1][2] + 1, d[i - j][3] + 1));
			}
			d[i][3] = min;
		}
		System.out.println(d[1000][3]);
	}

}

解法二

package provincialGames_09_2018;

public class A04_测试次数2 { // 19

	static final int N = 1000;
	static int[] f1 = new int[N + 1];
	static int[] f2 = new int[N + 1];
	static int[] f3 = new int[N + 1];// 记录手机数为1、2、3时,对应各层的测试次数

	public static void main(String[] args) {
		// 考虑一部手机的情况
		for (int i = 1; i <= N; i++) {
			f1[i] = i;
		}
		
		// 考虑两部手机的情况
		for (int i = 1; i <= N; i++) {
			int ans = Integer.MAX_VALUE;
			// 尝试1~i若干种方案, 最终记录所有方案中 次数最小的
			for (int j = 1; j <= i; j++) {// 在j层扔第一个手机
				// 1 好的 2 坏了
				int _max = 1 + Math.max(f2[i - j], f1[j - 1]);
				ans = Math.min(ans, _max);
			}
			f2[i] = ans;
		}

		// 考虑三部手机的情况
		for (int i = 1; i <= N; i++) {
			int ans = Integer.MAX_VALUE;
			// 尝试1~i若干种方案, 最终记录所有方案中 次数最小的
			for (int j = 1; j <= i; j++) {// 在j层扔第一个手机
				// 1 好的 2 坏了
				int _max = 1 + Math.max(f3[i - j], f2[j - 1]);
				ans = Math.min(ans, _max);
			}
			f3[i] = ans;
		}
		System.out.println(f3[N]);

	}

}

五、快速排序

标题:快速排序

以下代码可以从数组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));
    }
}

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

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

package provincialGames_09_2018;

import java.util.Random;

public class A05_快速排序 {

	public static int quickSelect(int a[], int l, int r, int k) {
		Random rand = new Random();
		int p = rand.nextInt(r - l + 1) + l;  //  [0, r + 1)
		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(a, i + 1, r, k - (i - l + 1)); //填空
    	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));
	}

}

六、递增三元组

标题:递增三元组

给定三个整数数组
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 


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


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。

解法一

package provincialGames_09_2018;

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

public class A06_递增三元组 {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		
		int a[] = new int[n];
		for(int i = 0; i < n; i++) {
			a[i] = sc.nextInt();
		}
		Arrays.parallelSort(a);
		
		int b[] = new int[n];
		for(int i = 0; i < n; i++) {
			b[i] = sc.nextInt();
		}
		Arrays.parallelSort(b);
		
		int c[] = new int[n];
		for(int i = 0; i < n; i++) {
			c[i] = sc.nextInt();
		}
		Arrays.parallelSort(c);
		
		int ans = 0;
		
		for(int i = 0; i < n; i++) {
			for(int j = 0; j < n; j++) {
				for(int k = 0; k < n; k++) {
					if(a[i] < b[j] && b[j] < c[k])
						ans++;
				}
			}
		}
		
		System.out.println(ans);
		
	}

}

解法二

当我们要排序的数据集很大时,parallelSort() 可能是更好的选择。
在数组较小的情况下,最好使用 sort(),因为它可以提供更好的性能。

package provincialGames_09_2018;

import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.Scanner;

public class A06_递增三元组2 {

	public static void main(String[] args) throws FileNotFoundException {
		long ans = 0;

		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();

		int a[] = new int[n];
		int b[] = new int[n];
		int c[] = new int[n];

		for (int i = 0; i < n; i++) {
			a[i] = sc.nextInt();
		}
		for (int i = 0; i < n; i++) {
			b[i] = sc.nextInt();
		}
		for (int i = 0; i < n; i++) {
			c[i] = sc.nextInt();
		}

		Arrays.sort(a);
		Arrays.sort(b);
		Arrays.sort(c);

		int p = 0, q = 0;
		for (int i = 0; i < n; i++) {
			while (p < n && a[p] < b[i]) {
				p++;
			}
			while (q < n && c[q] <= b[i]) {
				q++;
			}
			ans += 1L * p * (n - q);
		}

		System.out.println(ans);

	}

}

七、螺旋折线

标题:螺旋折线

如图p1.png所示的螺旋折线经过平面上所有整点恰好一次。  

p1.png


对于整点(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


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


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

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

dis(0, 1)=3
dis(-2, -1)=9
dis(1, 1)=4

package provincialGames_09_2018;

import java.io.FileNotFoundException;
import java.util.Scanner;

public class A07_螺旋折线 {

	// 以 右下角 对角线上的点 为 参照点,测算给定的点到参照点要走的距离

	public static void main(String[] args) throws FileNotFoundException {
		Scanner sc = new Scanner(System.in);
		long X = sc.nextLong(), Y = sc.nextLong();
		long d = 0; // 距离
		long n = 0; // 第几圈

		if (Y > 0 && Math.abs(X) <= Y) { // 点在上面的横线上
			n = Y; // 等差数列有多少项? Y项
			d = (Y - X) + (2 * Y); // X的最大值是Y,第一、四象限的距离---2Y
		} else if (X > 0 && Math.abs(Y) <= X) { // 点在最右边的横线上
			n = X;
			d = Y + X;
		} else if (Y <= 0 && X >= Y - 1 && X <= -Y) { // 点在最下边的横线上
			n = -Y;
			d = -(-Y - X);
		} else if (X < 0 && Y >= X + 1 && Y <= -X) { // 点在最左边的横线上
			n = -X - 1;
			d = -(Y - X - 1 - 2 * X - 1);
		}

		System.out.println(sum(1L, 2 * n, 1) * 2 - d);

	}

	/**
	 * 等差数列求和
	 * 
	 * @param a0  首项
	 * @param n  项数
	 * @param d  公差
	 * @return
	 */
	private static long sum(long a0, long n, int d) {
		return (2 * a0 + (n - 1) * d) * n / 2;
	}

}

八、日志统计

标题:日志统计

小明维护着一个程序员论坛。现在他收集了一份"点赞"日志,日志共有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  

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


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

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

 

package provincialGames_09_2018;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.SortedSet;
import java.util.TreeSet;

public class A08_日志统计 {

	// 存日志数据, ts-td分别是时刻及id,组合成对象, 存储在R中
	static class R { // 定义内部类
		int ts, td;// 时刻及id
	}

	public static void main(String[] args) throws FileNotFoundException {
//		System.setIn(new FileInputStream("E:\\in8.txt"));
//		System.setOut(new PrintStream("E:\\out8.txt"));

		Scanner sc = new Scanner(System.in);
		int N = sc.nextInt(), D = sc.nextInt(), K = sc.nextInt();
		R[] rs = new R[N];
		for (int i = 0; i < N; i++) {// 读取日志数据
			R r = new R();
			r.ts = sc.nextInt();
			r.td = sc.nextInt();
			rs[i] = r;
		}
		// 匿名内部类 定义 排序器
		Arrays.sort(rs, new Comparator<R>() {
			// 自定义 比较器
			// 按照时刻ts对一个记录R做升序排序
			@Override
			public int compare(R r1, R r2) {
				return r1.ts - r2.ts;
			}
		});

		// cnt: 用于给id计数 记录id及其出现的次数
		Map<Integer, Integer> cnt = new HashMap<Integer, Integer>();

		// answers: 用于存储答案(各个id), 因为要求答案输出有序, 这里直接用TreeSet
		SortedSet<Integer> answers = new TreeSet<Integer>();

		// 尺取法【通常是:双指针】
		int j = 0;// 移动哨兵---用于探测的指针
		for (int i = 0; i < N; ++i) {// i: 尺取法的起点---头部
			// 循环条件: i指向的时刻-i指向的时刻 < D
			while (j < N && rs[j].ts - rs[i].ts < D) {
				int td = rs[j].td;
				Integer exist = cnt.get(td);
				// 每一次循环,都要统计id,计数
				if (exist != null) {
					cnt.put(td, exist + 1);
				} else {
					cnt.put(td, 1);// id第一次出现
				}
				// 判断id数是否 >= K【判断是否满足条件】id放入answers中
				if (cnt.get(td) >= K) {
					answers.add(td);
				}
				j++;
			}
			// (马上i就要更新了)将上一个i对应的id的计数-1
			// 上一个区间, td的计数要扣除, 不干扰下一个区间的统计
			Integer cntOfI = cnt.get(rs[i].td);
			if (cntOfI != null) {
				cnt.put(rs[i].td, cntOfI - 1);
			}
		}
		// 输出答案---输出各个id
		for (Integer i : answers) {
			System.out.println(i);
		}

	}
}

九、全球变暖

标题:全球变暖

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

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

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

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

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

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

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

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

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

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

【输入样例】

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

【输出样例】
1  

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


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

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

package provincialGames_09_2018;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class A09_全球变暖 {

	static int[] dx = { -1, 1, 0, 0 }; // 四个方向 预定义数组
	static int[] dy = { 0, 0, -1, 1 }; // 四个方向

	private static int N;// 数据规模
	private static char[][] g; // 地图数据
	private static int[][] mark; // 标记数组 标记每个格子是否被访问

	private static int ans;// 结果:被完全淹没的岛屿数量

	// 自定义Point类型,存储一个格子的横纵坐标
	private static class Point {
		int x, y;
		public Point(int x, int y) {
			this.x = x;
			this.y = y;
		}
	}

	public static void main(String[] args) throws FileNotFoundException {
//		System.setIn(new FileInputStream(new File(("E:\\in9.txt"))));
		Scanner sc = new Scanner(System.in);
		N = sc.nextInt();
		sc.nextLine(); // 读取换行符

		// 初始化地图数据与标记数组
		g = new char[N][N];
		mark = new int[N][N];

		// 读取地图数据
		for (int i = 0; i < N; i++) {
			g[i] = sc.nextLine().toCharArray();
		}
		// 双循环检验#,从#开始宽度优先搜索
		// 双重循环检验地图上的各个格子,以未被访问的#为起点,做宽搜
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				if (g[i][j] == '#' && mark[i][j] == 0) {
					bfs(i, j); // 做标记 访问过的格子不再被访问
				}
			}
		}
		System.out.println(ans);
	}

	private static void bfs(int x, int y) {
		mark[x][y] = 1;// 标记 格子 为 已访问
		int cntOfBlock = 0; // 记录#陆地的数量
		int cntOfSwed = 0; // 记录和.相邻的#的数量 将被淹没的陆地的数量
		Queue<Point> queue = new LinkedList<Point>();// 新建队列
		queue.add(new Point(x, y));// 将当前格子封装到point,插入队列
		while (!queue.isEmpty()) {
			Point first = queue.poll();// 弹出头部
			cntOfBlock++;
			boolean swed = false;// 标记弹出的#四周是否有.
			// 探测四周
			for (int d = 0; d < 4; d++) {
				int nx = first.x + dx[d];
				int ny = first.y + dy[d];
				if (0 <= nx && nx < N && 0 <= ny && ny < N) {
					if (g[nx][ny] == '.') {
						swed = true;// 周边有一个.这块陆地就会被淹没,避免重复计数
					}
					if (g[nx][ny] == '#' && mark[nx][ny] == 0) {// 且‘#’没有被访问
						queue.add(new Point(nx, ny));
						mark[nx][ny] = 1;
					}
				}
			}
			// 陆地数量 与 被淹没陆地数量 相同,ans++
			if (swed) {
				cntOfSwed++;
			}
		}
		// 一个连通块就被访问完了, 块中#的数量记录在cnt1, 周边有.的#的数量记录在cnt2
		if (cntOfBlock == cntOfSwed) {
			ans++;
		}
	}

}

十、堆的计数

标题:堆的计数

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

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

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

    1
   / \
  2   3
 /
4

    1
   / \
  3   2
 /
4

    1
   / \
  2   4
 /
3

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


【输入格式】
一个整数N。  
对于40%的数据,1 <= N <= 1000  
对于70%的数据,1 <= N <= 10000  
对于100%的数据,1 <= N <= 100000

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

【输入样例】
4  

【输出样例】
3


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


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

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

  

package provincialGames_09_2018;

import java.util.Scanner;

public class A10_堆的计数 {

	static final int MOD = 1000000009;
	public static int N;
	static int[] size; // 记录每个节点的size
	static long[] jie; // 记录1~N的阶乘
	static long[] ni; // 记录1~N的阶乘的逆元(关于MOD)

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		N = sc.nextInt();
		size = new int[N + 1];
		jie = new long[N + 1];
		ni = new long[N + 1];
		initSize();
		initJie();
		System.out.println(dp());
	}

	private static long dp() {
		long[] d = new long[N + 1]; // d[i]表示的是i号节点作为根,小根堆的种数
		for (int x = N; x >= 1; x--) {
			if (2 * x + 1 <= N)
				d[x] = c(size[x] - 1, size[2 * x]) * d[2 * x] % MOD * d[2 * x + 1] % MOD;
			else if (2 * x <= N)
				d[x] = c(size[x] - 1, size[2 * x]) * d[2 * x] % MOD;
			else
				d[x] = 1;
		}
		return d[1];
	}

	private static void initJie() {
		jie[0] = 1;
		ni[0] = 1;
		for (int i = 1; i <= N; i++) {
			jie[i] = jie[i - 1] * i % MOD;
			ni[i] = pow(jie[i], MOD - 2);
		}
	}

	/**
	 * 快速求a的n次方
	 * 
	 * @param a
	 * @param n
	 * @return
	 */
	private static long pow(long a, int n) {
		if (a == 0)
			return 0;
		long ans = 1;
		long x = a;
		while (n > 0) {
			if ((n & 1) == 1)
				ans = ans * x % MOD;
			n >>= 1;
			x = x * x % MOD;
		}
		return ans;
	}

	static long c(int n, int r) {
		return jie[n] * ni[r] % MOD * ni[n - r] % MOD;
	}

	private static void initSize() {
		for (int i = N; i >= 1; i--) {
			size[i] = (2 * i <= N ? size[2 * i] : 0) + (2 * i + 1 <= N ? size[2 * i + 1] : 0) + 1;
		}
	}

}

小结

dfs

竞赛大纲

竞赛大纲A01_有n个孩子站成一圈

package provincialGames_09_2018;

import java.util.Vector;

public class 竞赛大纲A01_有n个孩子站成一圈 {

	public static void main(String[] args) {
		
		Vector a = new Vector();
		for(int i=1; i<=10; i++) {
			a.add("第" + i + "个孩子");
		}
		for(;;) {
			if(a.size()==1)
				break;
			for(int k=0; k<2; k++) {  //先移除,再添加:移除前两个元素  -->  把前两个元素移动到后面
				a.add(a.remove(0));  //【Java 组代码填空】
				//System.out.println("a.remove(0): " + a.remove(0));  //a.remove(0): 第2个孩子
			}
			a.remove(0);
		}
		System.out.println(a);

		/**
		Vector 中remove(int index)这个function的返回,是元素对象,而不是一般人认为的void.

		1 2 3 4 5 6 7 8 9 10
		-->先移除,再添加:移除前两个元素  -->  把前两个元素移动到后面
		3 4 5 6 7 8 9 10 1 2
		
		*/
		
		
		
		for(int i = 100; i <=999; i++) {
			if(i*i % 1000 == i) {
				System.out.println(i);
			}
		}
		
		
		
		//System.out.println("abcde".lastIndexOf("a"));  //0
		//System.out.println("abcde".charAt(0));  //a
		
		System.out.println(hasSameChar("a")); //false
		System.out.println(hasSameChar("abcdefg")); //false
		System.out.println(hasSameChar("abacdefag")); //true重复
		System.out.println(hasSameChar("abcdebfg")); //true重复
	}
	
	public static boolean hasSameChar(String s){
		if(s==null || s.length()<2) 
			return false;
		for(int i=0; i<s.length(); i++){
			char c = s.charAt(i);
			int k = s.lastIndexOf(c);
			if(i != k)   //if(____________________) 
				return true;
		}
		return false;
	}

}
/**
【编程大题】花朵数 一个 N 位的十进制正整数,如果它的每个位上的数字的 N 次方的和等于这个数本身, 
则称其为花朵数。 例如:当 N=3 时,153 就满足条件,因为 1^3 + 5^3 + 3^3 = 153,
这样的数字也被称为 水仙花数(其中,“^”表示乘方,5^3 表示 5 的 3 次方,也就是立方)。 
当 N=4 时,1634 满足条件,因为 1^4 + 6^4 + 3^4 + 4^4 = 1634。 当 N=5 时,92727 满足条件。 
实际上,对 N 的每个取值,可能有多个数字满足条件。 程序的任务是:求 N=21 时,所有满足条件的花朵数。
注意:这个整数有 21 位,它的 各个位数字的 21 次方之和正好等于这个数本身。 如果满足条件的数字不只有一个,
请从小到大输出所有符合条件的数字,每个数字占一 行。因为这个数字很大,请注意解法时间上的可行性。
要求程序在 1 分钟内运行完毕。 【程序运行参考结果】 128468643043731391252 449177399146038697307 



【Java 组代码填空】 有 n 个孩子站成一圈,从第一个 孩子开始顺时针方向报数,
报到 3 的人出列,下一个 人继续从 1 报数,直到最后剩下一个孩子为止。
问剩下第几个孩子。
下面的程序以 10 个孩 子为例,模拟了这个 过程,请完善之
(提示:报数的过程被与之逻辑等价的更容易操作的 过程所代替)。 



625 这个数字很特别,625 的平方等于 390625,刚好其末 3 位是 625 本身。
除了 625, 还有其它的 3 位数有这个特征吗?还有一个!
该数是:_____________ 
【参考答案】 376 



【代码填空--java】
下面的代码定义了一个方法 hasSameChar,用于判定一个给定的串中是否含有重复的字
符,比如“about”中,就没有重复的字符,而“telecom”,“aabaa”中都含有重复的字符,
其中“e”重复了 2 次,而“a”重复了 4 次,这些都算作有重复。
请根据方法的说明,分析给出的源程序,并填写划线部分缺失的代码。
注意,只填写缺少的,不要重复周围已经给出的内容,也不要填写任何说明性文字等。
public class A
{
	/*
	 判断串 s 中是否含有重复出现的字符
	 如果有重复则返回 true
	 其它情况返回 false
	
	 判断的思路是:从左到右扫描每个字符
	 对当前的字符,从右向左在 s 串中搜索它的出现位置,可以用 lastIndexOf 方法
	 如果找到的位置与当前的位置不同,则必然存在该字符的重复现象,即可返回 true
	 其它情况返回 false
	
	 在特殊情况下,比如传入的是空指针,或者 s 为空串,或者只含有 1 个字符,都不可能含有
	重复字符,
	 因此,这些情况直接返回 false
	
	public static boolean hasSameChar(String s){
		if(s==null || s.length()<2) return false;
		for(int i=0; i<s.length(); i++){
			char c = s.charAt(i);
			int k = s.lastIndexOf(c);
			if(____________________) return true;
		}
		return false;
	}
	public static void main(String[] args){
		System.out.println(hasSameChar("a")); //false
		System.out.println(hasSameChar("abcdefg")); //false
		System.out.println(hasSameChar("abacdefag")); //true
		System.out.println(hasSameChar("abcdebfg")); //true
	
	}
}
*/

竞赛大纲A02_信用卡号验证

package provincialGames_09_2018;

import java.util.Scanner;

public class 竞赛大纲A02_信用卡号验证 {

	private static final String XYZ = null;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		long l = sc.nextLong();  //16位
		int oddSum  = 0;  //奇数累加和
		int evenSum = 0;  //偶数累加和
		for(int i = 1; i <= 16; i++) {
			long t = l % 10;
			if(i % 2 != 0) {
				oddSum += t;
			} else {
				if(t * 2 >= 10) {
					evenSum += (t*2 - 9);
				} else {
					evenSum += t*2;
				}
			}
			l /= 10;
		}
		if( (oddSum + evenSum) % 10 == 0 ) {
			System.out.println("成功");
		} else {
			System.out.println("失败");
		}
	}

}
/**
【编程大题】信用卡号验证 
当你输入信用卡号码的时候,有没有担心输错了而造成损失呢?
其实可以不必这么担 心,因为并不是一个随便的信用卡号码都是合法的,
它必须通过 Luhn 算法来验证通过。 
该校验的过程: 
1、从卡号最后一位数字开始,逆向将奇数位(1、3、5 等等)相加。
2、从卡号最后一位数字开始,逆向将偶数位数字,
先乘以 2(如果乘积为两位数,则 将其减去 9),再求和。 
3、将奇数位总和加上偶数位总和,结果应该可以被 10 整除。 
例如,卡号是:5432123456788881 
则奇数、偶数位(用红色标出)分布:5432123456788881 
奇数位和=35 
偶数位乘以 2(有些要减去 9)的结果:1 6 2 6 1 5 7 7,求和=35。 
最后 35+35=70 可以被 10 整除,认定校验通过。 
请编写一个程序,从标准输入获得卡号,然后判断是否校验通过。
通过显示:“成功”, 否则显示“失败”。 

比如,用户输入:356827027232780 
程序输出:成功 
【程序测试参考用例】 
356406010024817     成功 
358973017867744     成功 
356827027232781     失败 
306406010024817     失败 
358973017867754     失败 
*/

竞赛大纲A03_砝码称重

package provincialGames_09_2018;

import java.util.Scanner;
import java.util.Stack;

public class 竞赛大纲A03_砝码称重 {

	public static void main(String[] args) {
		//System.out.println(Integer.toString(72, 37));

		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt(); // 1 - 121
		solve(n);
	}

	private static void solve(int n) {
		String str = Integer.toString(n, 3); // 3进制
		// 翻转后转换为字符数组
		char[] arr = new StringBuilder(str).reverse().toString().toCharArray();
		Stack<Integer> stack = new Stack();
		for (int i = 0; i < arr.length; i++) {
			if (arr[i] == '2') {
				stack.add(-1);
				if (i == arr.length - 1) {
					stack.add(1);
				} else
					++arr[i + 1];
			} else if (arr[i] == '3') {
				stack.add(0);
				if (i == arr.length - 1) {
					stack.add(1);
				} else
					++arr[i + 1];
			} else {
				stack.add(arr[i] - '0');
			}
		}
		StringBuilder sb = new StringBuilder();
		boolean b = true;
		while (stack.size() != 0) {
			int t = stack.pop();
			if (t == 1 && b) {
				sb.append("").append((int) Math.pow(3, stack.size()));
				b = false;
			} else if (t == 1)
				sb.append("+").append((int) Math.pow(3, stack.size()));
			else if (t == -1)
				sb.append("-").append((int) Math.pow(3, stack.size()));
		}
		System.out.println(sb.toString());
	}

}
/**

【编程大题】
用天平称重时,我们希望用尽可能少的砝码组合称出尽可能多的重量。
如果只有 5 个砝码,重量分别是 1,3,9,27,81。则它们可以组合称出 1 到 121 之间
任意整数重量(砝码允许放在左右两个盘中)。
本题目要求编程实现:对用户给定的重量,给出砝码组合方案。
例如:
用户输入:
5
程序输出:
9-3-1
用户输入:
19
程序输出:
27-9+1
要求程序输出的组合总是大数在前小数在后。
可以假设用户的输入的数字符合范围 1~121。
【解题思路提示】
我们把已知的砝码序列记为:x1, x2, x3, x4, x5, x6 (这里多加一个标准砝码,为解题叙
述方便)
对于任意给定的重量 x,如果刚好等于 xi 则问题解决。
否则一定会位于两个标准砝码重量的中间,不妨设为:xi < x < xj
令 a = x – xi, b = xj – x
则,x 要么可以表示为: xi + a, 要么可以表示为: xj – b
这样问题就归结为怎样表示出 a 或 b
另一思路:对于每个 xi,可以乘以一个系数 ki,再求和。
ki 的数值无外乎:-1 0 1
这样,因为标准砝码的数量的很少的,我们就可以多层循环暴力组合 ki 来求解。
还有更“土气”但有效的思路:既然输入范围只有 120 左右,如果对每一种情况都做人
工求解,只要列一个大表,等查询的时候,直接输出答案就好了啊!但…这似乎是个耗时的
工程…

解题思路:可以用三进制解决,三进制上每一位都对应着一个砝码。
但是需要注意的是题目中的每一种砝码都只有一个。三进制中却是会出现2的。
所以需要对三进制进行改变;大体思想为:右边加两个砝码变成左边加一个右边加一个。
也就是说加两个砝码相当于加一个大的再减去一个小的。
在数字上的体现就是:将2变成-1更高位上进1。


	int arr[] = {1, 3, 9, 27, 81};
		boolean flag = true;
		for(int x: arr) {
			if(n == x) {
				System.out.println(x);
				flag = false;
			}
		}
		if(flag) {
			String str;
			int temp;
			for(int i = 0; i < arr.length-1; i++) {
				if( arr[i] < n && n < arr[i+1]) {
					int a = n - arr[i];
					int b = arr[i+1] - n;
					str = arr[i+1] + "-" + arr[i];
					temp = arr[i+1] - arr[i];
				}
			}
		}


数字类型的toString()方法可以接收表示转换基数(radix)的可选参数,
如果不指定此参数,转换规则将是基于十进制。同样,也可以将数字转换为其他进制数(范围在2-36)


var n = 17;
n.toString();//'17'
n.toString(2);//'10001'
n.toString(8);//'21'
n.toString(10);//'17'
n.toString(12);//'15'
n.toString(16);//'11'
*/

竞赛大纲A03_砝码称重2

package provincialGames_09_2018;

import java.util.Scanner;
import java.util.Stack;

public class 竞赛大纲A03_砝码称重2 {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int input = sc.nextInt();  //1 - 121
		int[] arr = new int[] {1, 2, 3};
		int[] a, b, c, d, e;
		a = b = c = d = e = new int[] {-1, 0, 1};
		for(int ai: a) {
			for(int bi: b) {
				for(int ci: c) {
					for(int di: d) {
						for(int ei: e) {
							if(input == ei*81 + di*27 + ci*9 + bi*3 + ai*1) {
								System.out.println( "(" + ei*81 + ")+(" + di*27 + ")+(" + ci*9 + ")+(" + bi*3 + ")+(" + ai*1 + ")" );
							}
						}
					}
				}
			}
		}
	}
	
}

竞赛大纲A03_砝码称重3

package provincialGames_09_2018;

import java.util.Scanner;
import java.util.Stack;

public class 竞赛大纲A03_砝码称重3 {

	public static void f(int n) {
		int[] sign = new int[] { -1, 0, 1 }; // 定义符号
		StringBuffer sb = new StringBuffer();
		for (int a : sign) {
			for (int b : sign) {
				for (int c : sign) {
					for (int d : sign) {
						for (int e : sign) {
							int i = a * 1;
							int j = b * 3;
							int k = c * 9;
							int l = d * 27;
							int m = e * 81;
							if (i + j + k + l + m == n) { // 找到结果
								// 如果不为0,则添加元�?,并在"正数"前添�?"+"�?
								sb.append(m != 0 ? (m > 0 ? "+" + m : m) : "");
								sb.append(l != 0 ? (l > 0 ? "+" + l : l) : "");
								sb.append(k != 0 ? (k > 0 ? "+" + k : k) : "");
								sb.append(j != 0 ? (j > 0 ? "+" + j : j) : "");
								sb.append(i != 0 ? (i > 0 ? "+" + i : i) : "");
								sb.deleteCharAt(0); // 去掉首元素的"+"�?;
								System.out.println(sb);
								return;
							}
						}
					}
				}
			}
		}
	}

	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		int n = scan.nextInt(); // 输入重量
		f(n);
	}

}

多谢观看~

猜你喜欢

转载自blog.csdn.net/weixin_44949135/article/details/108144284