第16届蓝桥杯省赛已经结束了,第一次参加也是坐牢了4个小时,现在还是来总结一下吧(先声明以下的解法,大家可以当作一种思路来看,解法不一定是正解,只是给大家提供一种能够正常想到的思路吧)
试题A:逃离高塔
本题其实没有什么难度,就是一个循环遍历即可,那么唯一需要注意的就是循环遍历的过程中,int是会爆的,这里需要用long来进行存储
public class Main{
public static void main(String[] args){
int ans=0;//记录最终答案
for(long i=1;i<=2025;i++){
long x=i*i*i;
if(n%10==3){
ans++;
}
}
System.out.println(ans);
}
}
最后进行的答案就是:202
试题B:消失的蓝宝
这题其实也是循环遍历即可,但是我们不能一个数一个数的去试,如果一个一个去遍历的话,好像是要跑2小时是可以跑出来,那么通过题目我们可以发现:
- N+20250412要能够被20240413整除
- N+20240413要能够被20250412整除
上述表达式我们可以理解为,这个数一定是20240413的倍数,并且可以发现20250412比20240413是要大9999,那么我们可以设一个数 n1 初始为20240413,然后循环从20240413开始遍历,n1 每次都加上一个20240413(因为最后的结果一定是20240413的倍数,所以其他数就没有必要一个一个去遍历了),然后再循环中我们定义 n2=n1-9999,然后判断如果当前的 n2%20250412==0?(我们每次加的都是20240413,这个数肯定是20240413的倍数,则无需再判断n1%20240413==0?),如果等于0那么再减去一个20250412就是最终答案!(因为我们是第一个表达式为基准的,所以要减去一个20250412)
public class Main{
public static void main(String[] args){
for(long n1=20240413L;n1<Long.MAX_VALUE;n1+=20240413){
long n2=n1-9999;
//判断
if(n2%20250412==0){
System.out.println(n1-20250412);
break;
}
}
}
}
最终答案就是:409876661809331
试题C:电池分组
这题就是一个位运算判断:要求将若干个数分为2组数字,那么这两组数字的异或和结果一样的话,一定是等于0的,这是为啥呢?举个例子:
例如样例的 1 2 3,1和2进行异或和后是3,那么3^3不就是0吗?所以我们只需要遍历一遍数组看看最后的异或结果是不是0即可(偷偷抱怨:这题这是太可惜了,考前1周都在学动态规划,考场看到这题还以为是01背包的选与不选的变种问题,最后还没写出来!!!)
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int t=scan.nextInt();
while(t-->0){
int n=scan.nextInt();
int ans=0;
for(int i=0;i<n;i++){
ans^=scan.nextInt();
}
if(ans==0){
System.out.println("YES");
}else{
System.out.println("NO");
}
}
}
}
试题D:魔法科考试
这题的考点就是判断素数的问题,其实就是两个循环遍历两个数组然后判断条件是否成立(需要的注意的是,这里会重复计算条件成立的同一个数,那么应该Set来过滤重复的数),再一个就是性能的问题,这里的数据是20000,如果使用朴素方法判断一个数是不是素数,那么最坏情况的时间复杂度就是n*m*log(a[i]+b[j]),这个时间复杂度是决定会超时的,在洛谷上这个时间复杂度是只能过8个案例的,所以我们应该提前筛好素数,然后在O(1)的时间复杂度判断是不是素数!(考场上我也没注意,使用的就是朴素的判断素数,这题也是拿不满的,可惜!!!)
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class Main{
static int[]prime=new int[20005];
static boolean st[]=new boolean[20005];
static int cnt=0;
static Set<Integer> set=new HashSet<>();
static int num;
public static void main(String[] args){
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
int m=scan.nextInt();
int []a=new int[n];
int []b=new int[m];
for(int i=0;i<n;i++){
a[i]=scan.nextInt();
}
for(int i=0;i<m;i++){
b[i]=scan.nextInt();
}
num=n+m;
//筛素数
creat();
//遍历枚举
int ans=0;//记录最终答案
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
int s=a[i]+b[j];
if(s<=num){
//判断是不是素数
if(set.contains(s)){
ans++;
set.remove(s);
}
}
}
}
System.out.println(ans);
}
public static void creat(){
//这是只需要筛选出num以内的素数即可,因为超过num的素数我们根本判断不到
for(int i=2;i<=num;i++){
if(!st[i]){
prime[cnt++]=i;
set.add(i);
}
for(int j=0;j<cnt;j++){
if(i*prime[j]>num)break;
st[i*prime[j]]=true;
if(i%prime[j]==0)break;
}
}
}
}
试题E:爆破
本题的核心就是在于,如何知道两个圆的最短距离:两个圆心之间的距离减去两个圆各自的半径,如果<=0那么就是相交的,如果不是那么就不是相交的
画图分析:(画图画的不好请见谅)
import java.util.Scanner;
public class Main{
static int g[][];
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
g=new int[n+1][3];
for(int i=1;i<=n;i++){
g[i][0]=scan.nextInt();
g[i][1]=scan.nextInt();
g[i][2]=scan.nextInt();
}
//创建n*n的表格
double dp[][]=new double[n+1][n+1];//dp[i][j]表示第i个圆和第j个圆之间的距离
double ans=0;//存放最后答案
for(int i=1;i<=n;i++){
double min=Double.MAX_EXPONENT;//寻找当前圆和其他圆的最小距离
for(int j=1;j<=n;j++){
//判断第i个圆和第j个圆的距离
//先判断是不是自身
if(i==j){
dp[i][j]=Double.MAX_EXPONENT;//因为我们最后要求一个最小的值,所以这里赋最大值
}else{
dp[i][j]=func(i,j);
}
min=Math.min(min,dp[i][j]);
}
ans+=min;
}
System.out.printf("%.2f",ans);
}
//判断距离
public static double func(int i,int j) {
//如果横坐标相同,直接判断纵坐标距离
if(g[i][0]==g[j][0]){
int len=Math.abs(g[i][1]-g[j][1]);//得到两个圆心的距离,再减去两个半径
len=len-(g[i][2]+g[j][2]);
//判断是不是小于0.小于0就是相交的,距离就是0
return len<=0?0:len;
}
//如果纵坐标相同,直接判断横坐标的距离
if(g[i][1]==g[j][1]){
int len=Math.abs(g[i][0]-g[j][0]);//得到两个圆心的距离,再减去两个半径
len=len-(g[i][2]+g[j][2]);
//判断是不是小于0.小于0就是相交的,距离就是0
return len<=0?0:len;
}
//此时是横纵坐标都不在一条线上,需要利用横纵坐标来结合勾股定理来得到两个圆心的距离
//我们以直角为基准,求两个临边的长度,然后通过勾股定理来求出对边(斜边)的长度
int lenx=Math.abs(g[i][0]-g[j][0]);
int leny=Math.abs(g[i][1]-g[j][1]);
//勾股
double len=Math.sqrt(lenx*lenx+leny*leny);
//此时得到两个圆心的位置,然后再减去两个圆的半径
len=len-(g[i][2]+g[j][2]);
return len<=0?0:len;
}
}
试题F:数组翻转
本题呢本质上来说就是找两个最大的连续区间,暴力+优化
根据样例分析:
4 4 3 3 2 1 3 以样例为例就是最后变成4 4 3 3 3 1 2
那我们可以拓展一下 4 4 3 3 2 1 3 3 4 4 4
那就是4 4 4 4 4 3 3 1 2 3 3
我们会发现翻转的最佳效果是把连续并且相同的数最大的和第二大的合并在一起
以下代码是暴力解法可能是会超时的(如果后续有更好的想法再做更新吧)
import java.util.Scanner;
public class Main{
static boolean st[];//判断当前数是不是查找过
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
int[]a=new int[n];
int max=0;
for(int i=0;i<n;i++){
a[i]=scan.nextInt();
max=Math.max(a[i],max);
}
st=new boolean[max+1];
long ans=0;//记录最终答案
for(int i=0;i<n;i++){
if(st[a[i]])continue;//此时说明当前数判断过了
int max1=0;//记录第一长的区间长度
int max2=0;//记录第二长的区间长度
int cnt=0;
for(int j=i;j<n;j++){
if(a[j]==a[i]){
cnt++;
}else{
//如果不是,那么我们记录一下之前的长度
if(cnt>max1){
max2=max1;
max1=cnt;
}else if(cnt>max2){
max2=cnt;
}
cnt=0;
}
}
if(cnt!=0){
if(cnt>max1){
max2=max1;
max1=cnt;
}else if(cnt>max2){
max2=cnt;
}
}
st[a[i]]=true;
//此时统计两个最长区间
ans=Math.max(ans,1l*a[i]*(max1+max2));
}
System.out.println(ans);
}
}
试题G:2的幂
本题暂时没有什么好的思路就先:略(如果有佬有想法可以评论在评论区)
...
试题H:研发资源分配
这题读完题目感觉就是一个全排列求最大价值问题,但是直接dfs肯定是会超时的(只能过20%的案例),所以可以试试贪心策略,为了使 A 部门获得的资源尽可能多,B 部门获得的资源尽可能少,每天都让 A 部门提交比 B 部门当天提交等级刚好大 1 的等级(如果存在),如果没有更大的等级,就选择最小的等级,避免资源作废。如果都选择不了,那么就只能判断相等的数能不能相互抵消了
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] b = new int[n];
for (int i = 0; i < n; i++) {
b[i] = scanner.nextInt();
}
boolean[] used = new boolean[n + 1];
int sumA = 0;
int sumB = 0;
for(int i=0;i<n;i++){
//找出当前只比b[i]大一个的数
int index=-1;//默认没找到
int max=Integer.MAX_VALUE;
for(int j=1;j<=n;j++){
if(j>b[i] && !used[j]){
//此时是找到了
index=j;
used[j]=true;
sumA+=i+1;
break;
}
}
//判断有没有找到
if(index==-1){
//此时说明没有找到,那么我们找最小的数
for(int j=1;j<=n;j++){
if(j<b[i] && !used[j]){
//此时是找到了
index=j;
used[j]=true;
sumB+=i+1;
break;
}
}
}
//此时判断等于的情况
if(!used[b[i]] && index==-1){
//此时可以找到相同的
sumA+=0;
sumB+=0;
used[b[i]]=true;
}
}
System.out.println(sumA-sumB);
}
}
总结
本次蓝桥杯相对前几届来说算法考的其实不多,主要还是逻辑思维问题, 我在考场上也只是做了一个填空和一个大题,大一第一次参加还是经验不够,总想着这题暴力肯定超时不愿意去写,一直坐在那里思考正解,但是这是非常不对的,我们应该先从暴力解开始优化才对,好歹写了还有一点分,再加上第一次参加肯定还是会紧张的,只能说明年继续努力吧!!!等到后面蓝桥云课加入了今年的题目,大家可以试试上述代码能通过几个案例哈(如果上述题解大佬们有更好的想法欢迎在评论区留言!!!)
平台声明:以上文章转载于《CSDN》,文章全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,仅作参考。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/2402_86304740/article/details/147252165