第十四届蓝桥杯javaA组2023年省赛初赛题解

题目pdf下载:第十四届蓝桥杯省赛pdf下载

目录

试题 A: 特殊日期

试题 B: 与或异或

试题 C: 平均

试题 D: 棋盘

试题 E: 互质数的个数

试题 F: 阶乘的和

试题 G: 小蓝的旅行计划

试题 H: 太阳

试题 I: 高塔

试题 J: 反异或 01 串


试题 A: 特殊日期

第十四届蓝桥杯javaA组2023年省赛初赛题解_第1张图片

 

题意:找出指定时间内,年数是月数和天数的倍数,也就是年数%月数==0

思路:模拟,我的答案是:35813063

就是用for来枚举天数,蓝桥杯挺经常出这个的

代码:暂无,回头补


试题 B: 与或异或

第十四届蓝桥杯javaA组2023年省赛初赛题解_第2张图片

题意:5个数从上往下,相邻的两个两两计算,运算符是&,或|,或^。已知这5个数,求多少种运算符情况可以最后答案是1

思路:dfs搜索,我的答案是:30528

dfs枚举所有运算符的排列情况,就是pow(3,10)=59049种,然后把这5个数从上往下计算,要是最后结果为1答案数+1。

代码(c++写的):

#include 
using namespace std;
int sum=0;
int a[100005];
int dp[10][10];
int mp[10][10];
void dfs(int d){
    if(d==11){
        for(int i=1;i<=4;i++) mp[1][i]=a[i];
        for(int i=1;i<=3;i++) mp[2][i]=a[i+4];
        for(int i=1;i<=2;i++) mp[3][i]=a[i+7];
        for(int i=1;i<=1;i++) mp[4][i]=a[10];
        for(int i=1;i<=4;i++){
            for(int j=1;j<=4-i+1;j++){
                if(mp[i][j]==0) dp[i][j]=dp[i-1][j]|dp[i-1][j+1];
                if(mp[i][j]==1) dp[i][j]=dp[i-1][j]^dp[i-1][j+1];
                if(mp[i][j]==2) dp[i][j]=dp[i-1][j]&dp[i-1][j+1];
            }
        }
        if(dp[4][1]==1)
            sum++;
        return;
    }
    a[d]=0;
    dfs(d+1);
    a[d]=1;
    dfs(d+1);
    a[d]=2;
    dfs(d+1);
}
int main()
{
    dp[0][1]=1;
    dp[0][2]=0;
    dp[0][3]=1;
    dp[0][4]=0;
    dp[0][5]=1;
    dfs(1);
    cout<

试题 C: 平均

第十四届蓝桥杯javaA组2023年省赛初赛题解_第3张图片

第十四届蓝桥杯javaA组2023年省赛初赛题解_第4张图片题意:给若干个数(范围是0-9),和他们的更改的花费,求最小花费,使得0-9最终数量相同

思路:贪心

只将数量>n/10的数改为其他数,也就是数量>n/10要改掉 (数量-n/10)个。当然是找其中最小的改

通过:思路的时间复杂度可以100%,具体通过看情况

代码:

import java.util.*;
public class Main{
	public static void main(String[] args){
		Scanner cin =new Scanner(System.in);
		int n=cin.nextInt();
		int A[][]=new int[11][100005];
		int len[]=new int[15];
		for(int i=1;i<=n;i++) {
			int x=cin.nextInt();
			int y=cin.nextInt();
			A[x][++len[x]]=y;
		}
		for(int i=0;i<10;i++) 
			Arrays.sort(A[i],1,len[i]+1);    //排序,不用list是因为没有板子,手敲不出来
		long sum=0;
		for(int i=0;i<10;i++) {
			for(int j=1;j<=len[i]-n/10;j++) {
				sum+=A[i][j];
			}
			
		}
		System.out.println(sum);
	}
}

试题 D: 棋盘

第十四届蓝桥杯javaA组2023年省赛初赛题解_第5张图片

 第十四届蓝桥杯javaA组2023年省赛初赛题解_第6张图片

题意:一个n*m的棋盘,开始全是白子,选择一个矩形全部反转,最后的棋盘情况打印一下

思路:差分前缀和

就是将这个矩形全部数+1(刚开始全是0),最后%2就是答案

因为最大数据也只是2000,每次在将要改变的行中,差分修改。总执行次数也不过是2000*2000。

最后逐行前缀和,打印这些数%2,注意打印时没有空格

通过:思路的时间复杂度可以100%,具体通过看情况

代码:

import java.util.*;
public class Main{
	public static void main(String[] args){
		Scanner cin =new Scanner(System.in);
		int n=cin.nextInt();
		int m=cin.nextInt();
		int A[][]=new int[2005][2005];
		for(int i=1;i<=m;i++) {
			int x1=cin.nextInt();
			int y1=cin.nextInt();
			int x2=cin.nextInt();
			int y2=cin.nextInt();
			for(int j=x1;j<=x2;j++) {
				A[j][y1]++;        //差分
				A[j][y2+1]--;
			}
		}
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=n;j++) {
				A[i][j]+=A[i][j-1];        //前缀和
				System.out.print(A[i][j]%2);
			}
			System.out.println();
		}
	}
}

试题 E: 互质数的个数

第十四届蓝桥杯javaA组2023年省赛初赛题解_第7张图片

题意:1-pow(a,b)中有多少个数,和pow(a,b)互质

思路:思维+gcd+快速幂

答案就是pow(a,b-1)*r,r是1-a中和a互质的数量

和a*a*a*a....互质,就是和a互质的数。

a,b互质就是gcd(a,b)==1。而(a,b)和(a,b+a),和(a,b+a*2)...的互质情况是一样的,求gcd()那个公式应该能看出来

也就是有循环,只看1-a就行

而r就是欧拉数,具体100%代码以后再写

通过:

我的代码只能过70%数据,因为是从1-a遍历(gcd时间logn)。要是欧拉函数求可以100%,而且b很大(1e18)要龟速乘算法了

70%的代码:

import java.util.*;
public class Main{
	static long mod=998244353;
	static long gcd(long a,long b){
	    return a==0?b:gcd(b%a,a);
	}
	static long qpow(long a,long b){
	    long ans=1;
	    while(b!=0){
	        if(b%2==1)
	            ans=ans*a%mod;
	        a=a*a%mod;
	        b/=2;
	    }
	    return ans;
	}
	public static void main(String[] args){
		Scanner cin =new Scanner(System.in);
		long a=cin.nextLong();
		long b=cin.nextLong();
	    long r=0;
	    for(int i=1;i

100%代码:

1

试题 F: 阶乘的和

第十四届蓝桥杯javaA组2023年省赛初赛题解_第8张图片

题意:

思路:这题没有比较好的思路。

只有用乘法求余公式,暴力计算最大的m。

ans=1,2,6,24,120...。计算这些阶乘的和是否是能被ans其整除,也就是判断:

A[1]!%ans+A[2]!%ans+....+A[n]!%ans==0

要是不行的话,就输出当前ans对应的阶乘数。

通过:

可以看到方法不一定能过前40%,但是大多情况下,也有可能过些

代码:

import java.util.*;
public class Main{
	public static void main(String[] args){
		Scanner cin =new Scanner(System.in);
		int n=cin.nextInt();
		int a[]=new int[n+10];
		for(int i=1;i<=n;i++) {
			a[i]=cin.nextInt();
		}
		long ans=1,p=1;
		while(true) {
			long sum=0;
			for(int i=1;i<=n;i++) {
				long res=1;
				for(int j=2;j<=a[i];j++) {
					res=res*j%ans;
				}
				sum=(sum+res)%ans;        //算和
			}
			if(sum==0) {
				ans*=(++p);
			}else {
				break;
			}
		}
		System.out.println(p-1);
	}
}

试题 G: 小蓝的旅行计划

第十四届蓝桥杯javaA组2023年省赛初赛题解_第9张图片

第十四届蓝桥杯javaA组2023年省赛初赛题解_第10张图片

题意:

思路:思维+优先队列

这题思路还是比较简单,就是把前面的所有能买的单价和其数量记录下来,然后一旦没有油就从中去除最小的价格。

100%的思路应该是优先队列,存储长度为2的list,每次弹出最小价格,并修改其数量。一旦为0就不再压入。

但是第一步,我就忘了优先队列和重写比较方法的代码

于是我用了set,将一个价格放很多个,且放入价格*10000+(一个数),防止set的去重,只能过60%数据。

通过:

优先队列,存储长度为2的list可以100%;我写的set只能60%

set代码(60%):

import java.util.*;
public class Main{
	public static void main(String[] args){
		Scanner cin =new Scanner(System.in);
		Set s=new TreeSet();
		int A[]=new int[1000000];
		int n=cin.nextInt();
		int m=cin.nextInt();
		long sum=0;
		for(int i=1;i<=n;i++) {
			int x=cin.nextInt();
			int y=cin.nextInt();
			int z=cin.nextInt();
			m-=x;
			while(m<0) {
				if(s.isEmpty()) {
					sum=-1;
					i=n+1;
					break;
				}
				int r=(int)s.iterator().next();
				sum+=r/10000;
				s.remove(r);
				m++;
			}
			for(int j=1;j<=z;j++) {
				s.add(y*10000+(++A[y]));
			}
		}
		System.out.println(sum);
	}
}

优先队列(100%)代码:

1

试题 H: 太阳

第十四届蓝桥杯javaA组2023年省赛初赛题解_第11张图片

 第十四届蓝桥杯javaA组2023年省赛初赛题解_第12张图片

题意:给若干个线段,和一个光源。判断有多少个线段可以被光源找到

思路:计算几何

100%的思路没有,只有30%的,也就是双for判断有没有被其他挡到

显示判断可能被挡的,高度至少是被挡<档<光源 or 被挡>档>光源 才有可能会挡到

接下来是被挡线段的两个端点,连接光源后不能与挡的线段相交

方法是叉积求两个线段不相交,要在两点同一侧才不相交

通过:

该思路时间复杂度可以30%,再优的没有想到

判断i是否会被j挡到的代码:

这个代码判断高度那里有问题,导致样例答案是1,最后又改后样例是2对了。回头再改这个代码

	static int solve(int i,int j) {	
		if((b[i]<=y && y<=b[j]) || (b[j]<=y && y<=b[i]))  //高度要合适
			return 0;
		double h1=add(new Node(a[j],b[j]),new Node(a[i],b[i]),new Node(x,y));
		double h2=add(new Node(a[j]+l[j],b[j]),new Node(a[i],b[i]),new Node(x,y));
		if((h1*h2)<0) return 1;
        //叉积<0,返回1(表示被挡,因为boolean也忘了咋写用了int)
		h1=add(new Node(a[j],b[j]),new Node(a[i]+l[i],b[i]),new Node(x,y));
		h2=add(new Node(a[j]+l[j],b[j]),new Node(a[i]+l[i],b[i]),new Node(x,y));
		if((h1*h2)<0) return 1;
		return 0;
	}

代码:

import java.util.*;
public class Main{
	static int n,x,y;
	static int a[]=new int[1000000],b[]=new int[1000000],l[]=new int[1000000];
	static double add(Node a,Node x,Node y) {
		return (a.x-x.x)*(a.y-y.y)-(a.y-x.y)*(a.x-y.x);
	}
	static int solve(int i,int j) {	
		if((b[i]<=y && y<=b[j]) || (b[j]<=y && y<=b[i]))
			return 0;
		double h1=add(new Node(a[j],b[j]),new Node(a[i],b[i]),new Node(x,y));
		double h2=add(new Node(a[j]+l[j],b[j]),new Node(a[i],b[i]),new Node(x,y));
		if((h1*h2)<0) return 1;
		h1=add(new Node(a[j],b[j]),new Node(a[i]+l[i],b[i]),new Node(x,y));
		h2=add(new Node(a[j]+l[j],b[j]),new Node(a[i]+l[i],b[i]),new Node(x,y));
		if((h1*h2)<0) return 1;
		return 0;
	}
	public static void main(String[] args){
		Scanner cin =new Scanner(System.in);
		n=cin.nextInt();
		x=cin.nextInt();
		y=cin.nextInt();
		for(int i=1;i<=n;i++) {
			a[i]=cin.nextInt();
			b[i]=cin.nextInt();
			l[i]=cin.nextInt();
		}
		int sum=0;
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=n;j++) {
				if(i!=j && solve(i,j)==1) {
					break;
				}
				if(j==n) sum++;
			}
		}
		System.out.println(sum);
	}
}
class Node{
	public double x,y;
	public Node(){}
	public Node(double a,double b){
		this.x=a;
		this.y=b;
	}
}

试题 I: 高塔

第十四届蓝桥杯javaA组2023年省赛初赛题解_第13张图片

第十四届蓝桥杯javaA组2023年省赛初赛题解_第14张图片

 样例算不出来,什么都没有

通过:0%

试题 J: 反异或 01 串

第十四届蓝桥杯javaA组2023年省赛初赛题解_第15张图片

第十四届蓝桥杯javaA组2023年省赛初赛题解_第16张图片题意:

思路:前缀和+回文字串判断

这种题思路感觉细究下就会错

我的思路:反异或操作后,字串是为0为中心的回文串,长度为偶数的回文串。只有一次这个操作,且其他都是在两边添加0和1,那么这个回文字串一定还在给的字符串中

所以在其中找回文子串,我用的中心扩展法。用1的数量=左端点的左边1的数量+右端点的右边1的数量+回文字串中的1数量/2

也就是O(n的平方)求出所有情况的最小1的数量

通过:

时间复杂度是O(n的平方),也就是60%。

O(n)或者O(nlogn)求回文子串(不是最长)不知道有没有方法。当然是建立在这个思路正确的前提下

代码:

import java.util.*;
public class Main{
	static String s;
	static int f[]=new int[1000000];
	static int n,l=0,r=0,mi=10000000;
	static long mod=998244353;
	static int get(int x,int y){        //前缀和
	    if(y<1 || x>n || x>y) return 0;
	    return f[y]-f[x-1];
	}
	static void solve(){
	    while(l-1!=0 && r+1!=n+1 && s.charAt(l-1)==s.charAt(r+1)){
	        l--;
	        r++;
	    }
	    mi=Math.min(mi,get(l,r)/2+get(1,l-1)+get(r+1,n));
	}
	public static void main(String[] args){
		Scanner cin =new Scanner(System.in);
	    s=cin.next();
	    n=s.length();
	    s=" "+s;
	    for(int i=1;i<=n;i++){
	        f[i]+=f[i-1]+(s.charAt(i)=='1'?1:0);
	    }
	    for(int i=1;i<=n;i++){
	        if(s.charAt(i)=='0'){
	            l=i;
	            r=i;
	            solve();
	        }
	        if(i!=n && s.charAt(i)==s.charAt(i+1)){
	            l=i;
	            r=i+1;
	            solve();
	        }
	    }
	    System.out.println(mi);
	}
}

没有代码的资料,好多东西都不会用

你可能感兴趣的:(#,比赛题解,蓝桥杯,c++,职场和发展)