第九届蓝桥杯省赛(Java B)

1.第几天
2000年的1月1日,是那一年的第1天。
那么,2000年的5月4日,是那一年的第几天?
注意:需要提交的是一个整数,不要填写任何多余内容。

思路:直接excel,两个日期相差124天,由于2000/1/1算第一天,所以ans=125。

2.方格计数
如图所示,在二维平面上有无数个1x1的小方格。
在这里插入图片描述
我们以某个小方格的一个顶点为圆心画一个半径为1000的圆。
你能计算出这个圆里有多少个完整的小方格吗?
注意:需要提交的是一个整数,不要填写任何多余内容。

思路:这题首先可以把圆分成四份,从四个象限来看,以第一象限为例,每次从一个小方格的右上角计算,判断这个点到圆心的距离与半径的关系,如果小于半径,方格数加一,最后的答案再乘以4即可。

public class B {
	public static void main(String[] args) {
		int r = 1000;
		long sum = 0;
		for (int i = 1; i <= 1000; ++i) {
			for (int j = 1; j <= 1000; ++j) {
				double d = Math.sqrt(i * i + j * j);
				if (d <= r) {
					sum++;
				}
			}
		}
		System.out.println(4 * sum);
	}
}

3.复数幂
设i为虚数单位。对于任意正整数n,(2+3i)^n 的实部和虚部都是整数。
求 (2+3i)^123456 等于多少? 即(2+3i)的123456次幂,这个数字很大,要求精确表示。
答案写成 “实部±虚部i” 的形式,实部和虚部都是整数(不能用科学计数法表示),中间任何地方都不加空格,实部为正时前面不加正号。(2+3i)^2 写成: -5+12i,
(2+3i)^5 的写成: 122-597i
注意:需要提交的是一个很庞大的复数,不要填写任何多余内容。

思路:首先模拟一下运算过程,设a+bi,c+di,相乘之后,新的实部是ac-bd,新的虚部是ad+bc,由于本题数据规模实在是太大了,需要用BigInteger来运算,在eclipse控制台显示的是–i,在记事本显示的是个巨大的数。。

import java.math.BigInteger;

public class C {

	public static void main(String[] args) {
		BigInteger a = new BigInteger("2");
		BigInteger b = new BigInteger("3");
		BigInteger c = new BigInteger("2");
		BigInteger d = new BigInteger("3");
		BigInteger t = BigInteger.ZERO;
		for (int i = 2; i <= 123456; ++i) {
			// 循环进来的时候已经是默认是(2+3i)^1
			t = a.multiply(c).subtract(b.multiply(d));
			b = a.multiply(d).add(b.multiply(c));
			a = t;
		}
		if (b.compareTo(BigInteger.ZERO) > 0) {
			System.out.println(a + "+" + b + "i");
		} else {
			System.out.println(a + "" + b + "i");
		}
	}
}

output:…
在这里插入图片描述

5.快速排序
以下代码可以从数组a[]中找出第k小的元素。
它使用了类似快速排序中的分治算法,期望时间复杂度是O(N)的。
请仔细阅读分析源码,填写划线部分缺失的内容。

import java.util.Random;

public class E {
	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(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, 2));
	}
}

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
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

思路:这题最容易想到的就是直接暴力,三重for循环进行判断,这个应该大家都写的出,但是数据规模大肯定会超时,这里需要用到二分中的lower_bound和upper_bound函数,c++里面才有,java选手只能手打了。。
我们可以以B数组作为中间量,判断在A数组中小于B[i]的元素有多少,判断在C数组中大于B[i]的元素有多少。

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

public class F {

	public static int lower_bound(int[] a, int start, int end, int key) {

		while (start < end) {
			int mid = start + (end - start) / 2;
			if (a[mid] < key) {
				start = mid + 1;
			} else {
				end = mid;
			}
		}
		return start;
	}
	public static int upper_bound(int[] a, int start, int end, int key) {
		while (start < end) {
			int mid = start + (end - start) / 2;
			if (a[mid] <= key) {
				start = mid + 1;
			} else {
				end = mid;
			}
		}
		return start;
	}

	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		int n = cin.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] = cin.nextInt();
		}
		for (int i = 0; i < n; ++i) {
			b[i] = cin.nextInt();
		}
		for (int i = 0; i < n; ++i) {
			c[i] = cin.nextInt();
		}
		Arrays.sort(a, 0, n);
		Arrays.sort(b, 0, n);
		Arrays.sort(c, 0, n);
		long sum = 0;
		for (int i = 0; i < n; ++i) {
			int ret1 = lower_bound(a, 0, n, b[i]);
			int ret2 = n - upper_bound(c, 0, n, b[i]);
			sum += (ret1 * ret2);
		}
		System.out.println(sum);
	}
}

7.螺旋折线
在这里插入图片描述
如图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
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

思路:这题我们可以先把上图转成下面这个图在这里插入图片描述

import java.util.Scanner;

public class G {

	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		long x = cin.nextLong();
		long y = cin.nextLong();
		// 在第几个矩形
		long index = Math.max(Math.abs(x), Math.abs(y));
		// 之前的正方形长度和
		long sum = 0;
		if (index > 1) {
			long t = index - 1;
			long t1 = index - 1;
			while (t-- > 0) {
				sum += 8 * (t1);
				t1--;
			}
		}
		// 计算点(-index,-index)到点(x,y)的距离
		long ans = 0;
		long tx = -index, ty = -index;
		long d1 = x - tx, d2 = y - ty;
		// 在前半段,直接相减得到答案
		if (y > x) {
			ans += (d1 + d2);
		} else {
			// 后半段,先求出距离,再用这个三角形的边长减去这个距离
			ans += (8 * index - d1 - d2);
		}
		System.out.println(ans + sum);
	}
}

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
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

思路:自定义一个cmp,然后统计在这个时间段内点赞的数量是否满足题意,不是很确定能不能过全部,自己测试了几组貌似是对的。。

import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Scanner;

class Node {
	int ts;
	int id;
	int cnt;
}

class cmp implements Comparator<Node> {
	public int compare(Node x, Node y) {
		if (x.id == y.id) {
			return x.ts - y.ts;
		}
		return x.id - y.id;
	}
}

public class H {
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		int n = cin.nextInt();
		int d = cin.nextInt();// d时间
		int k = cin.nextInt();// 赞的个数
		Node[] blog = new Node[100005];
		for (int i = 0; i < n; ++i) {
			blog[i] = new Node();
		}
		for (int i = 0; i < n; ++i) {
			int a = cin.nextInt();
			int b = cin.nextInt();
			blog[i].ts = a;
			blog[i].id = b;
			blog[i].cnt = 0;
		}
		Arrays.sort(blog, 0, n, new cmp());
		int fg = 0;
		for (int i = fg; i < n; ++i) {
			int time = blog[i].ts + d;
			blog[i].cnt++;
			for (int j = i + 1; j < n; ++j) {
				if (blog[i].id != blog[j].id) {
					fg = j;
					break;
				} else {
					if (blog[j].ts < time) {
						blog[i].cnt++;
					}
				}
			}
		}
		HashSet<Integer> set = new HashSet<Integer>();
		for (int i = 0; i < n; ++i) {
			if (blog[i].cnt >= k) {
				set.add(blog[i].id);
			}
		}
		Object[] ans = set.toArray();
		for (int i = 0; i < ans.length; ++i) {
			System.out.println(ans[i]);
		}
	}
}

9.全球变暖
你有一张某海域NxN像素的照片,".“表示海洋、”#"表示陆地,如下所示:
在这里插入图片描述
其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有2座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
................................#................
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
【输入格式】
第一行包含一个整数N。 (1 <= N <= 1000)
以下N行N列代表一张海域照片。
照片保证第1行、第1列、第N行、第N列的像素都是海洋。
【输出格式】
一个整数表示答案。
【输入样例】
7
........##.....##........##...####....###........
【输出样例】
1
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

思路:根据题意我们可以知道四周全是陆地的岛屿是不会被淹没的,所以我们可以直接dfs,然后在dfs的过程中需要判断岛屿的四周是否全是陆地,如果是,那么我们用一个ans数组存起来,并且ans[i]++,表示这个岛屿不会被消失,最后统计的时候遍历ans数组,看ans数组中为0的个数就是消失的岛屿数。

import java.util.Scanner;

public class I {
	static int n;
	static int sum = 0;
	static int[] ans = new int[1005];// 记录四周都是陆地的陆地块
	static boolean[][] vis = new boolean[1005][1005];
	static char[][] mp = new char[1005][1005];

	public static void dfs(int x, int y, int k) {
		if (x < 0 || x >= n || y < 0 || y >= n || mp[x][y] == '.' || vis[x][y]) {
			return;
		}
		vis[x][y] = true;
		if (mp[x - 1][y] == '#' && mp[x + 1][y] == '#' && mp[x][y - 1] == '#' && mp[x][y + 1] == '#') {// 四周全是陆地
			ans[k]++;
		}
		dfs(x + 1, y, k);
		dfs(x - 1, y, k);
		dfs(x, y + 1, k);
		dfs(x, y - 1, k);

	}

	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		n = cin.nextInt();
		String[] str = new String[1005];
		for (int i = 0; i < n; ++i) {
			str[i] = cin.next();
		}
		for (int i = 0; i < n; ++i) {
			for (int j = 0; j < n; ++j) {
				mp[i][j] = str[i].charAt(j);
			}
		}
		for (int i = 0; i < n; ++i) {
			for (int j = 0; j < n; ++j) {
				if (!vis[i][j] && mp[i][j] == '#') {
					dfs(i, j, sum);
					sum++;
				}
			}
		}
		int cnt = 0;
		for (int i = 0; i < sum; ++i) {
			if (ans[i] == 0) {
				cnt++;
			}
		}
		System.out.println(cnt);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值