2025蓝桥杯JAVA编程题练习Day6
1.小计算器
题目描述
模拟程序型计算器,依次输入指令,可能包含的指令有
-
数字:'NUMX',X 为一个只包含大写字母和数字的字符串,表示一个当前进制的数。
-
运算指令:'ADD','SUB','MUL','DIV','MOD',分别表示加减乘,除法取商,除法取余。
-
进制转换指令:'CHANGE K',将当前进制转换为 K 进制(2≤K≤36)。
-
输出指令:'EQUAL',以当前进制输出结果。
-
重置指令:'CLEAR',清除当前数字。
指令按照以下规则给出:
数字,运算指令不会连续给出,进制转换指令,输出指令,重置指令有可能连续给出。
运算指令后出现的第一个数字,表示参与运算的数字。且在该运算指令和该数字中间不会出现运算指令和输出指令。
重置指令后出现的第一个数字,表示基础值。且在重置指令和第一个数字中间不会出现运算指令和输出指令。
进制转换指令可能出现在任何地方。
运算过程中中间变量均为非负整数,且小于 263。
以大写的'A'~'Z'表示 10~35。
输入描述
第 1 行:1 个n(1≤n<5×10^5),表示指令数量。
第 2 ⋯n+1行:每行给出一条指令。指令序列一定以'CLEAR'作为开始,并且满足指令规则。
初始默认的进制是十进制。
输出描述
依次输出每一次 'EQUAL' 得到的结果。
输入输出样例
输入
7
CLEAR
NUM 1024
CHANGE 2
ADD
NUM 100000
CHANGE 8
EQUAL
输出
2040
AC代码
import java.util.*;
public class exercise1 {
static Scanner scan=new Scanner(System.in);
public static void main(String[] args) {
int t=scan.nextInt();
long ans=0;
int sys=10;
String str=null; // 当运算时确定操作符
boolean flag=false;
while(t-->0) { //先判断t再减
String s=scan.next(); //空格之前的,不包含空格后
if(s.equals("CLEAR")) {
ans=0;
flag=false;
}else if(s.equals("NUM")) {
String n=scan.next();
if(!flag) {
// flag为false表示初始赋值
ans=Long.parseLong(n, sys);
flag=true; // 之后的为运算数
}else {
long m=Long.parseLong(n,sys);
if(str.equals("ADD")) {
ans+=m;
}else if(str.equals("SUB")) {
ans-=m;
}else if(str.equals("MUL")) {
ans*=m;
}else if(str.equals("DIV")) {
ans/=m;
}else if(str.equals("MOD")) {
ans%=m;
}
}
}else if(s.equals("EQUAL")) {
System.out.println(Long.toString(ans,sys).toUpperCase());
}else if(s.equals("CHANGE")) {
sys=scan.nextInt();
}else { // 运算指令(只有操作符)
str=s;
flag=true;
}
}
}
}
2.小数第n位
题目描述
我们知道,整数做除法时,有时得到有限小数,有时得到无限循环小数。
如果我们把有限小数的末尾加上无限多个 0,它们就有了统一的形式。
本题的任务是:在上面的约定下,求整数除法小数点后的第 nn 位开始的 3 位数。
输入描述
输入一行三个整数:a b na b n,用空格分开。aa 是被除数,bb 是除数,nn 是所求的小数后位置(0<a,b,n<1090<a,b,n<109)
输出描述
输出一行 3 位数字,表示:aa 除以 bb,小数后第 nn 位开始的 3 位数字。
输入输出样例
输入
1 8 1
输出
125
AC代码
(1)过20%样例,暴力
import java.util.*;
public class exercise1 {
static Scanner scan=new Scanner(System.in);
public static void main(String[] args) {
long a=scan.nextInt();
long b=scan.nextInt();
long n=scan.nextInt();
String s=Double.toString((a*1.0)/(b*1.0));
long idx=s.indexOf(".");
long tt=idx+n;
for(int i=1;i<=3;i++) {
if(tt>=s.length())System.out.print(0);
else System.out.print(s.charAt((int)tt));
tt++;
}
}
}
3.类斐波那契循环数
问题描述
对于一个有 n 位的十进制数 N=d1d2d3…dn,可以生成一个类斐波那契数列S,数列 S 的前 nn 个数为:
{S1=d1,S2=d2,S3=d3,…,Sn=dn}
数列 S 的第 k(k>n) 个数为:
∑Si(i=k-n到k-1)
如果这个数 N 会出现在对应的类斐波那契数列 S 中,那么 N 就是一个类斐波那契循环数。
例如对于 197,对应的数列 S 为:
{1,9,7,17,33,57,107,197,…}
197 出现在 S 中,所以 197 是一个类斐波那契循环数。
请问在 0 至 10^7 中,最大的类斐波那契循环数是多少?
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
解题要点
- 求最大,则从最大到小枚举
- 对于n个数,数组num只需要0到n-1,因为求和也只求0到n-1。因为每次求完和都放在后面,且不断向后n个n个求和,因此只需把结果使用取模的方式放到num中。(如num[j%n]=sum)
- 求和数组可以使用:sum=Arrays.stream(num).sum()
AC代码
import java.util.*;
public class exercise1{
public static Scanner scan=new Scanner(System.in);
public static void main(String[] args) {
for(int i=10000000;i>0;i--) {
if(check(i)) {
System.out.println(i);
break;
}
}
}
public static boolean check(int x) {
String s=x+"";
int n=s.length();
int[] num=new int[n];
for(int i=0;i<n;i++) {
num[i]=s.charAt(i)-'0';
}
int sum=0;
for(int i=n;sum<x;i++) {
sum=Arrays.stream(num).sum();//数组求和
num[i%n]=sum;
}
//循环退出为sum>=x
return sum==x;
}
}
4.分布式队列
问题描述
小蓝最近学习了一种神奇的队列: 分布式队列。简单来说,分布式队列包含 N 个节点(编号为 0 至 N−1,其中 0 号为主节点),其中只有一个主节点,其余为副节点。
主/副节点中都各自维护着一个队列,当往分布式队列中添加元素时,都是由主节点完成的(每次都会添加元素到主节点对应的队列的尾部);副节点只负责同步主节点中的队列。可以认为主/副节点中的队列是一个长度无限的一维数组,下标为 0,1,2,3…,同时副节点中的元素的同步顺序和主节点中的元素添加顺序保持一致。
由于副本的同步速度各异,因此为了保障数据的一致性,元素添加到主节点后,需要同步到所有的副节点后,才具有可见性。
给出一个分布式队列的运行状态,所有的操作都按输入顺序执行。你需要回答在某个时刻,队列中有多少个元素具有可见性。
输入格式
第一行包含一个整数 N,表示节点个数。
接下来包含多行输入,每一行包含一个操作,操作类型共有以下三种: add、sync 和 query,各自的输入格式如下:
-
addelement: 表示这是一个添加操作,将元素 element 添加到队列中;
-
syncfollowerid: 表示这是一个同步操作,followerid 号副节点会从主节点中同步下一个自己缺失的元素;
-
query: 查询操作,询问当前分布式队列中有多少个元素具有可见性。
输出格式
对于每一个 query操作,输出一行,包含一个整数表示答案。
样例输入
3
add 1
add 2
query
add 1
sync 1
sync 1
sync 2
query
sync 1
query
sync 2
sync 2
sync 1
query
样例输出
0
1
1
3
样例说明
执行到第一个 query时,队列内容如下:
0: [1,2]
1: []
2: []
两个副节点中都无元素,因此答案为 0。
执行到第二个 query 时,队列内容如下:
0: [1,2,1]
1: [1,2]
2: [1]
只有下标为 0 的元素被所有节点同步,因此答案为 1 。
执行到第三个 query 时,队列内容如下:
0: [1,2,1]
1: [1,2,1]
2: [1]
只有下标为 0 的元素被所有节点同步,因此答案为 1。
执行到第四个 query 时,队列内容如下:
0: [1,2,1]
1: [1,2,1]
2: [1,2,1]
三个元素都被所有节点同步,因此答案为 3。
解题要点
- 对处理不限定数量的输入(一行一行),采用while(scan.hasNext())
- 对于中间有空格,可以使用String op=scan.next(),只接收到空格前
AC代码
import java.util.*;
public class exercise1{
public static Scanner scan=new Scanner(System.in);
public static void main(String[] args) {
int n=scan.nextInt();
int[] count=new int[n];
while(scan.hasNext()) { //对于处理不限定的输入
String op=scan.next();//空格前
if(op.equals("add")) {
int x=scan.nextInt();//其实可以不用管,接收就好了
count[0]++;
}else if(op.equals("sync")) {
int x=scan.nextInt();
count[x]=Math.min(count[0], count[x]+1);
}else {
int res=count[0];
for(int i=1;i<n;i++) {
res=Math.min(res, count[i]);
}
System.out.println(res);
}
}
}
}
5.食堂
问题描述
S 学校里一共有 a2个两人寝、a3 个三人寝,a4个四人寝,而食堂里有 b4 个四人桌和 b6 个六人桌。学校想要安排学生们在食堂用餐,并且满足每个寝室里的同学都在同一桌就坐,请问这个食堂最多同时满足多少同学用餐?
输入格式
采用多组数据输入。
输入共 q+1 行。
第一行为一个正整数 q 表示数据组数。
后面 q 行,每行五个非负整数 a2,a3,a4,b4,b6表示一组数据。
输出格式
输出共 q 行,每行一个整数表示对应输入数据的答案。
样例输入
2
3 0 1 0 1
0 2 2 1 1
样例输出
6
10
样例说明
对于第一组数据,只有一个六人桌,因此最多安排三个两人寝的同学就餐,答案为 (2+2+2)=6(2+2+2)=6 。
对于第二组数据,用一个六人桌安排两个三人寝的同学,用一个四人桌安排一个四人寝的同学,答案为 (3+3)+(4)=10(3+3)+(4)=10 。
解题要点
- 先满足能够把桌子都坐满的情况。
- 然后再依次满足由缺1个到缺4个的情况。
AC代码
import java.util.*;
public class exercise1{
public static Scanner scan=new Scanner(System.in);
public static void main(String[] args) {
int n=scan.nextInt();
while(n-->0) {
int ans=0;
int a2=scan.nextInt();
int a3=scan.nextInt();
int a4=scan.nextInt();
int b4=scan.nextInt();
int b6=scan.nextInt();
//4-4人寝
while(b4>0&&a4>=1) {
b4--;a4--;ans+=4;
}
//2*2-4人寝
while(b4>0&&a2>=2) {
b4--;a2-=2;ans+=4;
}
//4+2-6人寝
while(b6>0&&a4>=1&&a2>=1) {
b6--;a4--;a2--;ans+=6;
}
//3+3-6人寝
while(b6>0&&a3>=2) {
b6--;a3-=2;ans+=6;
}
//2*3-6人寝
while(b6>0&&a2>=3) {
b6--;a2-=3;ans+=6;
}
//3剩1-4人寝
while(b4>0&&a3>=1) {
b4--;a3--;ans+=3;
}
//2+3剩1-6人寝
while(b6>0&&a2>=1&&a3>=1) {
b6--;a2--;a3--;ans+=5;
}
//2剩2-4人寝
while(b4>0&&a2>=1) {
b4--;a2--;ans+=2;
}
//4剩2-6人寝
while(b6>0&&a4>=1) {
b6--;a4--;ans+=4;
}
//2*2剩2-6人寝
while(b6>0&&a2>=2) {
b6--;a2-=2;ans+=4;
}
//3剩3-6人寝
while(b6>0&&a3>=1) {
b6--;a3--;ans+=3;
}
//2剩4-6人寝
while(b6>0&&a2>=1) {
b6--;a2--;ans+=2;
}
System.out.println(ans);
}
}
}
6.最优分组
问题描述
小蓝开了一家宠物店,最近有一种 X 病毒在动物之间进行传染,小蓝为了以防万一打算购买测试剂对自己的宠物进行病毒感染测试。
为了减少使用的测试剂数目,小蓝想到了一个好方法:将 N 个宠物平均分为若干组,使得每组恰好有 K 只宠物,这样对同一组的宠物进行采样并混合后用一个试剂进行检测,如果测试结果为阴性则说明组内宠物都未感染 X 病毒;如果是阳性的话则需要对组内所有 K 只宠物单独检测,需要再消耗 K 支测试剂(当 K=1 时,就没必要再次进行单独检测了,因为组内只有一只宠物,一次检测便能确认答案)。
现在我们已知小蓝的宠物被感染的概率为 p,请问 K 应该取值为多少才能使得期望的测试剂的消耗数目最少?如果有多个答案输出最小的 K。
输入格式
第一行,一个整数 N 。
第二行,一个浮点数 p 。
输出格式
输出一行,一个整数 K 表示答案。
样例输入
1000
0.05
样例输出
5
解题要点
- 一组K只宠物,那么没有宠物感染的概率就是P=(1-p)^K,至少有一只宠物感染的概率即1-P。
- 需要使用的药剂数量期望E=P*(N/K)+(1-P)*(N/K)+(1-P)*(N/K)*K。
- 首先第一个是没有宠物感染P,则有N/K组,则只需要P*(N/K)个药剂(一组一个);
- 然后第二个是有宠物感染(1-P),则有N/K组,第一轮只需要(1-P)*(N/K)个药剂(一组一个),第二轮在N/K组中其中有(1-P)*(N/K)个组是有感染的,因此对(1-P)*(N/K)个组每个组K个宠物再进行检测,即使用(1-P)*(N/K)*K个药剂。
AC代码
import java.util.*;
public class exercise1{
public static Scanner scan=new Scanner(System.in);
public static void main(String[] args) {
int n=scan.nextInt();
double p=scan.nextFloat();
int mink=Integer.MAX_VALUE;
double miny=Double.MAX_VALUE;
for(int k=n;k>=1;k--) {
if(n%k==0) { //(保证这个)能完整分完,答案更小
double P=Math.pow(1-p, k);
double E=(P+(1-P)*(1+k))*(n/k);
if(k==1)E=n;
if(E<=miny) {
miny=E;
mink=k;
}
}
}
System.out.println(mink);
}
}
7.星际旅行
问题描述
小明国庆节准备去某星系进行星际旅行,这个星系里一共有 n 个星球,其中布置了 m 道双向传送门,第 ii 道传送门可以连接 ai,bi 两颗星球(ai≠bi 且任意两颗星球之间最多只有一个传送门)。
他看中了一款 “旅游盲盒”,一共有 Q 个盲盒,第 i 个盲盒里的旅行方案规定了旅行的起始星球 xi 和最多可以使用传送门的次数 yi。只要从起始星球出发,使用传送门不超过规定次数能到达的所有星球都可以去旅行。
小明关心在每个方案中有多少个星球可以旅行到。小明只能在这些盲盒里随机选一个购买,他想知道能旅行到的不同星球的数量的期望是多少。
输入格式
输入共 m+Q+1 行。
第一行为三个正整数 n,m,Q 。
后面 m 行,每行两个正整数 ai,bi 。
后面 Q 行,每行两个整数 xi,yi 。
输出格式
输出共一行,一个浮点数(四舍五入保留两位小数)。
样例输入
3 2 3
1 2
2 3
2 1
2 0
1 1
样例输出
2.00
样例说明
第一个盲盒可以旅行到 1,2,3。
第二个盲盒可以旅行到 2。
第三个盲盒可以旅行到 1,2。
所以期望是 (3+1+2)/3=2.00。
解题要点
- 传送门可以连接两颗星球----》两个节点相连
- 只要从起始星球x出发,使用传送门不超过规定次数y能到达的所有星球都可以去旅行---》只要从起始点x,距离<=y都可以到达
- 求期望,即求概率,把从q个(xi起始点,yi距离)所能到达的点都加起来(可以重复),最后再除以q,则是我们最后要的答案
- 数据范围小使用floyd,用数组求节点到节点的最短距离,注意需要数组初始
- floyd数组初始:cnt[i][j]=一个较大的数(i!=j),且cnt[i][i]=0
- floyd得到结果:for(k):for(i):for(j):cnt[i][j]=min(cnt[i][j],cnt[i][k]+cnt[k][j])
AC代码
import java.util.*;
public class exercise1{
public static Scanner scan=new Scanner(System.in);
public static void main(String[] args) {
//某些节点相连,求规定起点和规定距离中能到达的最多的节点数
//传送门即节点相邻,使用传送门的次数即规定的距离
//求节点到节点的最短距离使用foyld
int n=scan.nextInt();
int m=scan.nextInt();
int q=scan.nextInt();
int[][] cnt=new int[n+1][n+1];
//数组初始!!
//还可以这样:for(int i=1;i<=n;i++)Arrays.fill(cnt[i], 10000);
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
cnt[i][j]=10000;
if(i==j)cnt[i][j]=0;
}
}
for(int i=1;i<=m;i++) {
int a=scan.nextInt();
int b=scan.nextInt();
cnt[a][b]=1;
cnt[b][a]=1;
}
//floyd
for(int k=1;k<=n;k++) {
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
cnt[i][j]=Math.min(cnt[i][j], cnt[i][k]+cnt[k][j]);
}
}
}
int ans=0;
for(int i=1;i<=q;i++) {
int x=scan.nextInt();//起点x
int y=scan.nextInt();//距离y
int count=0;
for(int j=1;j<=n;j++) {
//只要从起始点出发,距离<=y都可以到达
if(cnt[x][j]<=y)count++;
}
ans+=count;
}
//求期望
System.out.printf("%.2f",ans*1.0/q);
}
}
8.过年
问题描述
蓝桥村的村民们正准备迎接新年。他们计划宰杀 N 头猪,以庆祝一整年的辛勤劳作和丰收。每头猪的初始位置位于下标 xi,所有 xi均为偶数,保证没有两头猪初始位置相同。
当猪意识到人类打算宰杀它们时,并非束手就擒。它们会主动移动以寻找同伴,遵循以下规则:
- 每头猪以恒定速率朝着最近的另一头猪移动。若有多头猪距离相同,则选择朝着坐标更小的猪移动。所有猪的移动速度相同。
- 当两只猪相遇在同一坐标时,它们会融合成一个整体,被视为一头猪。
当所有猪聚集在同一坐标点时停止移动。现在村民们想要确定最终猪群聚集的确切坐标位置,请你帮助解决这个问题。
输入格式
第一行输入一个整数 N(2≤N≤105)表示猪的数量。
第二行输入 N 个整数 x1,x2,⋯,xN(−109≤xi≤109) 表示每头猪的坐标,保证 x1,x2,⋯xN 是偶数,且各不相同。
输出格式
输出一个整数表示答案。
样例输入
5
0 -2 -4 10 2
样例输出
3
解题要点
- 首先要将坐标从小到大进行排序
- 使用少量样例(如4个点),观察找规律
AC代码
import java.util.*;
public class exercise1{
public static Scanner scan=new Scanner(System.in);
public static void main(String[] args) {
//假设n=4:-2、0、2、4, (从小到大排序)
//(-2+0)/2=-1,(2+4)/2=3,(-1+3)/2=1
//也就是(-2+4)/2=1
int n=scan.nextInt();
int[] x=new int[n];
for(int i=0;i<n;i++) {
x[i]=scan.nextInt();
}
Arrays.sort(x);
System.out.println((x[0]+x[n-1])/2);
}
}
9.最大比例
题目描述
X 星球的某个大奖赛设了 M 级奖励。每个级别的奖金是一个正整数。
并且,相邻的两个级别间的比例是个固定值。
也就是说:所有级别的奖金数构成了一个等比数列。比如:16,24,36,54,其等比值为:3/2
现在,我们随机调查了一些获奖者的奖金数。
请你据此推算可能的最大的等比值。
输入描述
第一行为数字 N(0<N<100),表示接下的一行包含 N 个正整数
第二行 N 个正整数 Xi(Xi<109),用空格分开。每个整数表示调查到的某人的奖金数额
输出描述
一个形如 A/B 的分数,要求 A、B 互质。表示可能的最大比例系数 测试数据保证了输入格式正确,并且最大比例是存在的。
输入输出样例
输入
3
1250 200 32
输出
25/4
解题要点
- 求最大公约数gcd:long gcd(a,b):return b==0?a:gcd(b,a%b)
AC代码
import java.util.*;
public class exercise1{
public static Scanner scan=new Scanner(System.in);
public static void main(String[] args) {
int n=scan.nextInt();
long[] x=new long[n];
for(int i=0;i<n;i++) {
x[i]=scan.nextLong();
}
Arrays.sort(x);
long minx=Long.MAX_VALUE;
long miny=Long.MAX_VALUE;
for(int i=0;i+1<n;i++) {
if(x[i]!=x[i+1]) {
long gg=gcd(x[i],x[i+1]);
miny=Math.min(x[i+1]/gg, miny);
minx=Math.min(x[i]/gg, minx);
}
}
System.out.println(miny+"/"+minx);
}
public static long gcd(long a,long b) {
return b==0?a:gcd(b,a%b);
}
}
10.特殊日期
问题描述
对于一个日期,我们可以计算出年份的各个数位上的数字之和,也可以分别计算月和日的各位数字之和。请问从 1900 年 1 月 1日至 9999 年 12 月 31 日,总共有多少天,年份的数位数字之和等于月的数位数字之和加日的数位数字之和。
例如,2022年 11月 13日满足要求,因为 2+0+2+2=(1+1)+(1+3)。
请提交满足条件的日期的总数量。
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
解题要点
- 4,6,9,11-30天(剩下31天,2月闰年29,非闰年28)。
- 对四位数y进行分解时是这样的:y/1000+y/100%10+y/10%10+y%10(不断取最后一位)
- 判断闰年:if( (y%4==0&&y%100!=0) || (y%400==0) ),如果成立则是闰年
AC代码
import java.util.*;
public class exercise1{
public static Scanner scan=new Scanner(System.in);
public static void main(String[] args) {
int ans=0;
int[] month= {0,31,28,31,30,31,30,31,31,30,31,30,31};
for(int y=1900;y<=9999;y++) {
for(int m=1;m<=12;m++) {
int maxd=month[m];
if(m==2&&check(y))maxd+=1;
for(int d=1;d<=maxd;d++) {
if((y/1000+y/100%10+y/10%10+y%10)==(m/10+m%10+d/10+d%10)) {
ans++;
}
}
}
}
System.out.println(ans);
}
public static boolean check(int y) {
if((y%4==0&&y%100!=0)||(y%400==0)) {
return true;
}
return false;
}
}