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


题解思路及源码,来自 蓝桥杯 郑未老师。java

   

目录程序员

1、第几天算法

2、方格计数编程

3、复数幂数组

测试app

测试——输出到文件dom

解法一ide

解法二性能

4、测试次数测试

解法一

解法二

5、快速排序

6、递增三元组

解法一

解法二

7、螺旋折线

8、日志统计

9、全球变暖

10、堆的计数

小结

竞赛大纲

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

竞赛大纲A02_信用卡号验证

竞赛大纲A03_砝码称重

竞赛大纲A03_砝码称重2

竞赛大纲A03_砝码称重3


1、第几天

标题:第几天

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


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

【答案】:125

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

2、方格计数

标题:方格计数

如图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);

	}

}

3、复数幂

标题:复数幂

设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");
	}

}

4、测试次数

标题:测试次数

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];// 记录手机数为一、二、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]);

	}

}

5、快速排序

标题:快速排序

如下代码能够从数组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));
	}

}

6、递增三元组

标题:递增三元组

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

	}

}

7、螺旋折线

标题:螺旋折线

如图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,第1、四象限的距离---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;
	}

}

8、日志统计

标题:日志统计

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

	}
}

9、全球变暖

标题:全球变暖

你有一张某海域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++;
		}
	}

}

10、堆的计数

标题:堆的计数

咱们知道包含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,不然按无效代码处理。

 稍后更新。。。

小结

暂无!

竞赛大纲

竞赛大纲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 算法来验证经过。 
该校验的过程: 
一、从卡号最后一位数字开始,逆向将奇数位(一、三、5 等等)相加。
二、从卡号最后一位数字开始,逆向将偶数位数字,
先乘以 2(若是乘积为两位数,则 将其减去 9),再求和。 
三、将奇数位总和加上偶数位总和,结果应该能够被 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);
	}

}

多谢观看~