试题 B: 类斐波那契循环数
我发现蓝桥杯的题目现在就是要费时间去理解,所以还是审题很重要,这道题的思路就是,一个n位数的前n个数,都是对应的位数上的值,比如说12345,五位数是吧,那数列S的前五位数就是{1,2,3,4,5},后面的数的值就是不断的从该位置上的前n位数进行相加就可以得到对应的数据,我们的算法思路就是,直接暴力,这个数据也不大,循环10^7 *,计算机一两秒就能直接算出来,我们只需要不断获取这个范围的数值上的位数,累计相加和为sum,再判断在对应的数列s中是否存在sum与对应的N相等的数值就可以了,过程仔细一些就行了,难度不大。
public class Main {
static int END = 10000000;
public static void main(String[] args) {
int MaxNumber = 0;
for(int i = 1; i <= END; i ++) { // 由1开始
int number =i;
String numberAsString =String.valueOf(number);
int Length =numberAsString.length();
int Array[] = new int[Length];
NumbertoArray(Array, i);
int k = 0;
while(true) {
//这里我们不断向前推进一位数,然后进行length长度的相加
Array[k] = ListNumberSum(Array);
// 要么是类斐波那契循环数要么不是,直接更新k
//准备下一个循环
if(Array[k] == i || Array[k] > i) break;
k = (k + 1) % Length;
}
if(Array[k] == i) { // 是的话更新MaxNumber
if(MaxNumber <= i) {
MaxNumber = i;
}
}
}
System.out.println(MaxNumber);//运行结果7913837
}
public static void NumbertoArray(int array[], int number) {
for(int i = array.length - 1; i >= 0; i --) {
array[i] = number % 10;
number = number / 10;
}
}
public static int ListNumberSum(int array[]) {
int sum = 0;
for(int i = 0; i < array.length; i ++) sum = sum + array[i];
return sum;
}
}
试题 C: 分布式队列
题目描述
小蓝最近学习了一种神奇的队列:分布式队列。简单来说,分布式队列包含 N 个节点(编号为 0 至 N − 1,其中 0 号为主节点),其中只有一个主节点,其余为副节点。主/副节点中都各自维护着一个队列,当往分布式队列中添加元素时都是由主节点完成的(每次都会添加元素到队列尾部);副节点只负责同步主节点中的队列。可以认为主/副节点中的队列是一个长度无限的一维数组,下标为 0, 1, 2, 3 . . . ,同时副节点中的元素的同步顺序和主节点中的元素添加顺序保持一致。
由于副本的同步速度各异,因此为了保障数据的一致性,元素添加到主节点后,需要同步到所有的副节点后,才具有可见性。
给出一个分布式队列的运行状态,所有的操作都按输入顺序执行。你需要回答在某个时刻,队列中有多少个元素具有可见性。
输入格式
第一行包含一个整数 N,表示节点个数。接下来包含多行输入,每一行包含一个操作,操作类型共有以下三种:add、sync 和 query,各自的输入格式如下:
1. add element:表示这是一个添加操作,将元素 element 添加到队列中;
2. sync follower_id:表示这是一个同步操作,follower_id 号副节点会从主节点中同步下一个自己缺失的元素;
3. 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]
执行到第三个 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。
【评测用例规模与约定】
对于 30% 的评测用例:1 ≤ 输入的操作数 ≤ 100。
对于 100% 的评测用例:1 ≤ 输入的操作数 ≤ 2000,1 ≤ N ≤ 10,1 ≤follower_id < N,0 ≤ element ≤ 105。
这套题罗里吧嗦一大堆,不仔细看真的容易审题不清晰,而且很容易被误导,这道题难就难在题目理解上,这道题我们其实可以不用管副节点, 而且主节点添加了什么元素,以及副节点添加了什么元素,是否与主节点相等,你全都不用管,你只要在意主节点要添加元素的时候,你就往里面添加就好了,这个题目的意思就是,副节点会自动填充,我们不需要管,那这就好办了,我们只需要每次在显现元素的时候,找到所有队列中元素最少的就好了。
import java.io.PrintWriter;
import java.util.*;
public class Main {
final static PrintWriter out=new PrintWriter(System.out);
public static void main(String[] agrs) {
Scanner sc =new Scanner(System.in);
int n =sc.nextInt();
long vi[] =new long[n];//vi[0]为主队列,1到(n-1)为副队列
while(sc.hasNext()) {
String op =sc.next();
if(op.equals("add")) {
int i =sc.nextInt();
vi[0]++;//增加主队列元素总数
}else if(op.equals("add")) {
int i =sc.nextInt();
vi[i]=vi[0]<vi[i]+1?vi[i]:vi[i]+1;//同步副队列i中的个数
}else if(op.equals("query")) {
out.println(find(vi));
}
}
out.flush();
out.close();
}
private static char[] find(long[] arr) {
// TODO Auto-generated method stub
long min =0x3f3f3f3f;
for(int i =0;i<arr.length;i++) {
min =Math.min(min, arr[i]);
}
}
return min;
}
试题 D: 食堂
题目描述
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。
对于第二组数据,用一个六人桌安排两个三人寝的同学,用一个四人桌安排一个四人寝的同学,答案为 (3 + 3) + (4) = 10。
【评测用例规模与约定】
对于 20% 的评测用例,保证 a2 + a3 + a4 ≤ 8。对于 100% 的评测用例,保证 q ≤ 100,b4 + b6 ≤ a2 + a3 + a4 ≤ 100。
这道题我们需要使用到贪心算法+分类讨论,要仔细一些,对各种情况进行讨论。
优先使用六人桌:因为六人桌可以容纳更多的学生,我们应该首先尝试用六人桌来安排学生。
安排三人寝和两人寝:如果有三人寝,我们可以用一张六人桌来安排两个三人寝,或者安排三个两人寝。
试题 E: 最优分组
这道题没什么好说的了,这个跟高中的那种概率题很像,纯数学的题目,把公式列出来就出结果了。
期望值就是E(X)=N/K+(1-(1-P)^K)*N
来解释一下这个公式,这道题是混合检验,我们分成了N/K组,那么每一组都要用一次试剂,那么这个数量是固定的,如果我们检查到了有阳性,那么会被检测到阳的组数是(1-(1-P)^K)*N/K,这个组每一个都要被检查一次,那么要再乘以K,所以就为(1-(1-P)^K)*N。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc =new Scanner(System.in);
int N =sc.nextInt();
double p =sc.nextInt();
double MinHope =N;
int bestK =1;
for(int k =1;k<=N;k++){
if (N%k==0){
double GetHope =N*(1-Math.pow(1-p,k)+N/k)+N/k;
if (GetHope<MinHope){
MinHope=GetHope;
bestK =k;
}
}
}
System.out.println(bestK);
}
}
试题 F:星际旅行
这道题的话,下面的解题思路就是,借助Dilkstra的思想,首先就是先设置一个流程去判断不同星球之间的连接情况,边权设置为1,map用来存储某个星球和其他星球的连接状态,最后借助这个map去计算期望值,这道题还是有点难实现代码的,注意审题。
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.PriorityQueue;
public class Main {
static BufferedReader in =new BufferedReader(new InputStreamReader(System.in));//用于读取输入
static PrintWriter out =new PrintWriter(new OutputStreamWriter(System.out));//用于输出结果
public static void main(String[] args) throws IOException {
String[] s =in.readLine().split("\\s");//读取一行数据,
int n =Integer.parseInt(s[0]);//星球数量
int m =Integer.parseInt(s[1]);//连接数
int q =Integer.parseInt(s[2]);//查询次数
//优先队列用于Dijkstra算法,存储星球以及到达星球的最短距离
PriorityQueue<long[]> pq =new PriorityQueue<>((o1, o2) ->Long.compare(o1[1],o2[1]));
//数组列表数组,用于存储星球之间的连接关系和距离
List<int[]>[] lists =new ArrayList[n+1];
for (int i =1;i<=n;i++){
lists[i]=new ArrayList<>();
}
//二维数组,存储星球之间的距离,初始值设为Long.MAX_VALUE
long[][] map =new long[n+1][n+1];
for (long[] v:map) Arrays.fill(v,Long.MAX_VALUE);
//读取连接关系,将连接关系存储在list数组中
int a,b;
for (int i =0;i<m;i++){
s=in.readLine().split("\\s");
a =Integer.parseInt(s[0]);
b= Integer.parseInt(s[1]);
lists[a].add(new int[]{b,1});
lists[b].add(new int[]{a,1});//注意是双向连接
}
//使用Dijkstra算法计算每个星球到达其他星球的最短距离并存储在map数组中
for(int i =1;i<=n;i++){
//先将顶点到自身距离设置为0
map[i][i]=0l;
pq.add(new long[]{i,0l});
while (!pq.isEmpty()){
//移出一个具有最小距离的顶点
long[] v =pq.poll();
for (int[]x :lists[(int) v[0]]){//遍历与节点v[0]项链的所有节点x
if (v[1]+x[1]<map[i][x[0]]) {
map[i][x[0]] = v[1] + x[1];
pq.add(new long[]{x[0], map[i][x[0]]});
}
}
}
}
//统计查询结果
long sum =0l;
for(int k =0;k<q;k++){
s=in.readLine().split("\\s");
a=Integer.parseInt(s[0]);
b=Integer.parseInt(s[1]);
for (int i =1;i<=n;i++){
if (map[a][i]<b){
sum++;
}
}
//计算平均可以到达星球数量,并输出结果
out.printf("%.2f",1.0*sum/q);
out.flush();
}
}
}