第九届蓝桥杯javaB组
一、标题:第几天
标题:第几天
2000年的1月1日,是那一年的第1天。 那么,2000年的5月4日,是那一年的第几天?
注意:需要提交的是一个整数,不要填写任何多余内容。
答案:125
数一下就可以
二、标题:方格计数
标题:方格计数
如图所示
在二维平面上有无数个1x1的小方格。 我们以某个小方格的一个顶点为圆心画一个半径为1000的圆。 你能计算出这个圆里有多少个完整的小方格吗?
注意:需要提交的是一个整数,不要填写任何多余内容。
**答案:**3137548
public class 方格计数 {
public static void main(String[] args) {
int r = 1000;
int ans = 0;
for (int i = 1; i <1000 ; i++) {
for (int j = 1; j <1000 ; j++) {
if (i*i+j*j<=1000*1000)
ans++;
}
}
System.out.println(ans*4);//别忘了乘以4,因为这是第一卦限的
}
}
(3)标题:复数幂
标题:复数幂
设i为虚数单位。对于任意正整数n,(2+3i)^n 的实部和虚部都是整数。
求 (2+3i)^123456 等于多少? 即(2+3i)的123456次幂,这个数字很大,要求精确表示。答案写成 “实部±虚部i” 的形式,实部和虚部都是整数(不能用科学计数法表示),中间任何地方都不加空格,实部为正时前面不加正号。(2+3i)^2 写成: -5+12i,
(2+3i)^5 的写成: 122-597i注意:需要提交的是一个很庞大的复数,不要填写任何多余内容。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CHV8rCdn-1649484263730)(…/…/…/typora/Images/捕获.PNG)]
$$
在java中有两个类,一个BigInteger类和BigDecimal类,分别代表大整数类和大浮点数类,在计算机内存足够大的情况下,理论上表示无限大的数
1、基本函数:
valueOf(parament):将参数转换为制定的类型
比如:int a = 3;
BigInteger b = BigInteger.valueOf(a);
则b=3;
String s = “12345”;
BigInteger c = BigInteger.valueOf(s);
则c=12345;
2.add():大整数相加
BigInteger a =new BigInteger(“23”);
BigInteger a =new BigInteger(“34”);
a.add(b);
3.subtract():相减
4.multiply():相乘
5.divide():相除取整
6.remainder()取余、
7.pow():a.pow(b)=a^b;
8.gcd():最大公约数
9.abs():绝对值
10.negate():取反数
11.mod():a.mod(b) = a%b =a.remainder(b);
12.max():min();
13.boolean equals():是否相等
14.BigInteger构造函数:
一般用于以下两种:
BigInteger(String val);
将指定字符串转换为十进制表示形式;
BigInteger(String val,int radix);
将指定基数的BigInteger的字符串表示形式转换为BigInteger
15
$$
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.math.BigInteger;
public class 复数幂 {
public static void main(String[] args) throws FileNotFoundException {
BigInteger a = BigInteger.valueOf(2);//a=2
BigInteger b = BigInteger.valueOf(3);
BigInteger c = BigInteger.valueOf(2);
BigInteger d = BigInteger.valueOf(3);
// (a+bi)*(c+di) =(ac-bd)+(ad+bc)i;
for (int i = 1; i <123456 ; i++) {
BigInteger A = a.multiply(c).subtract(b.multiply(d));
BigInteger B = a.multiply(d).add(c.multiply(b));
a = A;//如果不设置临时变量,后面b的值会出错,直接输出23i
b = B;
}
PrintStream out = System.out;
PrintStream printStream = new PrintStream(new File("ans.txt"));
System.setOut(printStream);//输出在ans.txt里
System.out.println(a.toString()+b.toString()+"i");
System.setOut(out);//如果注释了就不会输出在控制台里
System.out.println(a.toString()+b.toString()+"i");
}
}
(4)标题:测试次数
标题:测试次数
x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。
各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。x星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的2楼。
如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数=7。
特别地,如果手机从第1层扔下去就坏了,则耐摔指数=0。
如果到了塔的最高层第n层扔没摔坏,则耐摔指数=n为了减少测试次数,从每个厂家抽样3部手机参加测试。
某次测试的塔高为1000层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?
请填写这个最多测试次数。
注意:需要填写的是一个整数,不要填写任何多余内容。
一开始一位是贪心算法(在问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解),觉得
用二分法来做,后来看了解析之后竟然是用动态规划来做。转移的变量是当前手机的部数,和当然的楼层数。
答案:19
public class 测试次数 {
public static void main(String[] args) {
for (int i = 0; i <10 ; i++) {
for (int j = 0; j <10000 ; j++) {
memo[i][j] = 99999999;
}
}
System.out.println(f(3,1000));
}
private static int f(int m, int n) {
if (m==1)
return n;
if (n==1||n==2)
return 1;
if (memo[m][n]!=99999999)
{
return memo[m][n];
}
for (int i = 1; i <=n ; i++) {
memo[m][n] = Math.min(memo[m][n],1+Math.max(f(m,n-i),f(m-1,i)));
}
return memo[m][n];
}
static int[][] memo = new int[10][15555];
}
2022.4.8重新写一下这一题的思路:
利用动态规划解决题目,建立一个int类型数组dp[] [] ,dp[i] [j]代表楼层数为i时,手机数为j时,测试手机的耐摔指数时测试的次数。
设置总楼层为n层,总手机数目为m,在进行摔手机测试时有两种情况:第一种情况:在第i层摔手机时手机摔坏了,那么加下来需要测试的楼层数为i-1,测试的手机数为总手机数减1,即m-1;
第二种情况,在第i层摔手机没有摔坏,那么接下来需要测试的楼层数为总楼层数减去当前测试的楼层数,即n-i-1+1,测试的手机数为总手机数m。
题目中要求得到最坏运气下最多需要测试多少次才能确定手机的耐摔指数,设置测试次数min,最坏运气即两种情况下测试次数较多的一次,求最优解。
通过动态规划表达式为:
m
i
n
=
M
a
t
h
.
m
i
n
(
m
i
n
,
M
a
t
h
.
m
a
x
(
d
p
[
k
−
1
]
[
j
−
1
]
,
d
p
[
i
−
k
]
[
j
]
)
)
;
min = Math.min(min,Math.max(dp[k-1][j-1],dp[i-k][j]));
min=Math.min(min,Math.max(dp[k−1][j−1],dp[i−k][j]));
public class 测试次数 {
static int[][] memo = new int[10][15555];
//m是手机部数 n是楼层数
public static int f(int n, int m) {
// if (m == 1) return n;//只有一部手机,测试次数为楼层数
int[][] dp = new int[n + 1][n + 1];
// 只有一部手机时,测试次数为楼层数
for (int i = 1; i <n+1 ; i++) {
dp[i][1] = i;
}//只有一部手机,测试次数为楼层数,因为这是一个数组,不能用注释的第一行来做
for (int i = 1; i <= n; i++) {
for (int j = 2; j < m + 1; j++) {
// 表示int数据类型的最大取值数:2 147 483 647
// 最小为-2 147 483 648
int min = Integer.MAX_VALUE;
for (int k = 1; k <= i; k++) {
// 取最小值是最佳策略
min = Math.min(min,Math.max(dp[k - 1][j - 1], dp[i - k][j]));
// //在第k层摔坏了 dp[k-1][i-1] (下面k-1层,用j-1个手机去测试)
//在第k层没坏 dp[j-k][i] (上面的i-k层,用j个手机去测)
}
dp[i][j] = min+1;
}
}
return dp[n][m];
}
public static void main(String[] args) {
System.out.println(f(1000, 3));
}
}
(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));
}
}注意:只提交划线部分缺少的代码,不要抄写任何已经存在的代码或符号。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
一道代码填空题,这种第K小的元素其实是一道比较经典的例题,题目中这种思想可以快速求出元素中第k小的元素。答案:quickSelect(a,i+1,r,k - i + l - 1 )
答案:a,i+1,r,k-1-i+l
(6)标题:递增三元组
标题:递增三元组
给定三个整数数组
A = [A1, A2, … AN],
B = [B1, B2, … BN],
C = [C1, C2, … CN],
请你统计有多少个三元组(i, j, k) 满足:
- 1 <= i, j, k <= N
- 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,否则按无效代码处理。
方法一:三层for循环进行遍历
/*这种暴力的方法很好想,但是是超时的,可以可以*/
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[][] array = new int[3][n];
int[] min = new int[n+1];
int[] max = new int[n+1];
//输入数组
for (int i = 0; i <n ; i++) {
for (int j = 0; j <n ; j++) {
array[i][j] = scanner.nextInt();
}
}
//找到第一行中比第二行小的数字
for (int i = 0; i < n; i++) {
int sum = 0;
for (int j = 0; j <n ; j++) {
if (array[0][j]<=array[1][j])sum = sum+1;
}
min[i] = sum;
}
//找出第三行中比第二行大的,就是将个数存储在max数组中
for (int i = 0; i <n ; i++) {
int num = 0;
for (int j = 0; j <n ; j++) {
if (array[1][j]<=array[2][j])num = num+1;
}
max[i] = num;
}
// 比如第一行的第一个数字比中间行min【i】个数字小,*起来就可以
int ans = 0;
for (int i = 0; i <n ; i++) {
ans += max[i]*min[i];
}
System.out.println(ans);
}
那我们就进行优化:
/*使用前缀和进行优化
* 前缀和的特点就是在数据输入阶段对数据进行处理
* 为计算阶段提供前缀和数组,辅助计算
* 二分就是算出下标,然后用n-下标就是满足的个数
* 前缀和是直接输入的时候将每个数出现的次数存起来,就形成前缀和 数组、
* 最后一个测试点的结果连long都会溢出,最后改成Bigdecimal*/
package competition.realproblem9;
import java.util.Scanner;
public class Two递增三元组 {
static int[] a;
static int[] b;
static long[] ca;
static long[] cc;
static int[] c;
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt();
long ans = 0;
a = new int[N];
b = new int[N];
c = new int[N];
ca = new long[1000001];
cc = new long[1000001];
for (int i = 0; i < N; i++) {
a[i] = scanner.nextInt();
ca[a[i]]++; //前缀和的特点就行在输入阶段就将数据处理了
}
for (int i = 0; i < N; i++)
b[i] = scanner.nextInt();
for (int i = 0; i < N; i++) {
c[i] = scanner.nextInt();
cc[c[i]]++;
}
for (int i = 1; i < N; i++)
ca[i] += ca[i - 1];
for (int i = N; i > 0; i--)
cc[i - 1] += cc[i];
for (int i = 0; i < N; i++) {
if (b[i] != 0)
//因为ccca数组中存储的都是某个数就是他的下标,出现的次数,所以这里b【i】加1减1.
ans += ca[b[i] - 1] * cc[b[i] + 1];
}
System.out.println(ans);
}
}
(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请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。
下面有两种方法:方法一目前还不懂,方法二懂了
import java.util.Scanner;
//2022.02.06只懂2
public class 螺旋折线 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int X = scanner.nextInt();
int Y = scanner.nextInt();
int[] dx = {-1,0,1,0};
int[] dy = {0,1,0,-1};
long len = 0,dis = 1,res = 0;
int x0 = 0,y0 = 0,i = 0;
while (true)
{
x0+=dis*dx[i];
y0+=dis*dy[i];
len+=dis;
if (i==0&&X>=x0&&X<=x0+dis&&Y==y0)
{
System.out.println(len-(X-x0));
return;
}else if (i==1&&X==x0&&Y<=y0&&Y>=y0-dis)
{
System.out.println(len-(y0-Y));
return;
}
else if (i==2&&X<=x0&&X>=x0-dis&&Y==y0)
{
System.out.println(len-(x0-X));
return;
}else if (i==3&&X==x0&&Y>=y0&&Y<=y0+dis){
System.out.println(len-(Y-y0));
return;
}
i=(i+1)%4;
res++;
if (res==2)
{
res=0;
dis++;
}
}
}
}
import java.util.Scanner;
public class 螺旋折线2 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
long x = scanner.nextInt();
long y = scanner.nextInt();
scanner.close();
// 判断所在点所在的正方形:max(|x|,|y|)
long n = Math.max(Math.abs(x),Math.abs(y));//abs()绝对值的意思
long innerSum = 4*(n-1)*n;
// (3)计算:点(x,y)到点(-n,-n)的距离
// 过原点和(-n,-n)画一条辅助线
// 线上方的点:水平=(x+n),垂直=(y+n)
// 线下方的点可以折射为线上方的点,用外框正方形的周长去减即可
long sum = 0;
long dis1 = x+n;
long dis2 = y+n;
if (y>x){
// 线上方的点
sum+=(dis1+dis2);
}else {
// 线下方的点:所在正方形周长-折射之后的距离
sum+=(8*n-(dis1+dis2));
}
System.out.println(sum+innerSum);
}
}
(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,否则按无效代码处理。
import com.sun.xml.internal.bind.v2.util.QNameMap;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.*;
public class 日记统计 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
PrintWriter out = new PrintWriter(System.out);
int N = scanner.nextInt();
int D = scanner.nextInt();
int K = scanner.nextInt();
int ts,id;
scanner.close();
TreeMap<Integer,ArrayList<Integer>> hs = new TreeMap<Integer, ArrayList<Integer>>();
for (int i = 0; i < N; i++) {
ts = scanner.nextInt();
id = scanner.nextInt();
if (hs.containsKey(id)){
hs.get(id).add(ts);
}
else {
hs.put(id,new ArrayList<Integer>());
hs.get(id).add(ts);
}
for (Map.Entry<Integer, ArrayList<Integer>> x:hs.entrySet()){
Collections.sort(x.getValue());
for (int j = 0; j+K-1 <x.getValue().size(); j++) {
if (x.getValue().get(j+K-1)-x.getValue().get(j)<D)
{
out.println(x.getKey());
break;
}
}
}
out.close();
}
}
}
(9)标题:全球变暖
标题:全球变暖
你有一张某海域NxN像素的照片,".“表示海洋、”#"表示陆地,如下所示:
…
.##…
.##…
…##.
…####.
…###.
…其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有2座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
…
…
…
…
…#…
…
…请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
【输入格式】
第一行包含一个整数N。 (1 <= N <= 1000)
以下N行N列代表一张海域照片。照片保证第1行、第1列、第N行、第N列的像素都是海洋。
【输出格式】
一个整数表示答案。【输入样例】
7
…
.##…
.##…
…##.
…####.
…###.
…【输出样例】
1资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。
(10)标题:堆的计数
标题:堆的计数
我们知道包含N个元素的堆可以看成是一棵包含N个节点的完全二叉树。
每个节点有一个权值。对于小根堆来说,父节点的权值一定小于其子节点的权值。假设N个节点的权值分别是1~N,你能求出一共有多少种不同的小根堆吗?
例如对于N=4有如下3种:
1
/
2 3
/
41
/
3 2
/
41
/
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,否则按无效代码处理。