蓝桥杯2014年JavaB组省赛 (解析+代码)

第一题:武功秘籍

小明到X山洞探险,捡到一本有破损的武功秘籍(2000多页!当然是伪造的)。
他注意到:书的第10页和第11页在同一张纸上,但第11页和第12页不在同一张纸上。

小明只想练习该书的第81页到第92页的武功,又不想带着整本书。请问他至少要撕下多少张纸带走?

这是个整数,请通过浏览器提交该数字,不要填写任何多余的内容。
答案:7

第二题:切面条

一根高筋拉面,中间切一刀,可以得到2根面条。如果先对折1次,
中间切一刀,可以得到3根面条。如果连续对折2次,中间切一刀,可以得到5根面条。

那么,连续对折10次,中间切一刀,会得到多少面条呢?

答案是个整数,请通过浏览器提交答案。不要填写任何多余的内容。

找规律
切n刀时,可以得到2的n次方加1跟面条
答案:1025

第三题: 猜字母

把abcd…s共19个字母组成的序列重复拼接106次,得到长度为2014的串。
接下来删除第1个字母(即开头的字母a),以及第3个,第5个等所有奇数位置的字母。

得到的新串再进行删除奇数位置字母的动作。如此下去,最后只剩下一个字母,请写出该字母。

答案是一个小写字母,请通过浏览器提交答案。不要填写任何多余的内容。

答案:q

public static void main(String[] args){
        char[] a=new char[2014];
        int index=0;
        for(int i=1;i<=106;i++){
            for(int j=0;j<19;j++){
                a[index++]=(char)('a'+j);
            }
        }
        int len=2014;
        while(len!=1){
            int k=0;
            for(int i=1;i<len;i+=2){
                a[k++]=a[i];
            }
            len=k;
        }
        System.out.println(a[0]);
    }

第四题: 大衍数列

中国古代文献中,曾记载过“大衍数列”, 主要用于解释中国传统文化中的太极衍生原理。

它的前几项是:0、2、4、8、12、18、24、32、40、50 …

其规律是:对偶数项,是序号平方再除2,奇数项,是序号平方减1再除2。

以下的代码打印出了大衍数列的前 100 项。

for(int i=1; i<100; i++) {
if(________________) //填空
System.out.println(ii/2);
else
System.out.println((i
i-1)/2);
}

请填写划线部分缺失的代码。通过浏览器提交答案。

注意:不要填写题面已有的内容,也不要填写任何说明、解释文字

答案:i%2==0

第五题:圆周率

数学发展历史上,圆周率的计算曾有许多有趣甚至是传奇的故事。
其中许多方法都涉及无穷级数。

如图所示,就是一种用连分数的形式表示的圆周率求法。
在这里插入图片描述

下面的程序实现了该求解方法。实际上数列的收敛对x的初始值 并不敏感。

结果打印出圆周率近似值(保留小数点后4位,并不一定与圆周率真值吻合)。

double x = 111;
for(int n = 10000; n>=0; n–){
int i = 2 * n + 1;
x = 2 + (i*i / x);
}

System.out.println(String.format("%.4f", ______________));
答案:4/(x-1)

第六题:奇怪的分式

上小学的时候,小明经常自己发明新算法。一次,老师出的题目是:1/4 乘以 8/5

小明居然把分子拼接在一起,分母拼接在一起,答案是:18/45
在这里插入图片描述

老师刚想批评他,转念一想,这个答案凑巧也对啊,真是见鬼!

对于分子、分母都是 1~9 中的一位数的情况,还有哪些算式可以这样计算呢?

请写出所有不同算式的个数(包括题中举例的)。

显然,交换分子分母后,例如:4/1 乘以 5/8 是满足要求的,这算做不同的算式。

但对于分子分母相同的情况,2/2 乘以 3/3 这样的类型太多了,不在计数之列!

注意:答案是个整数(考虑对称性,肯定是偶数)。请通过浏览器提交。不要书写多余的内容。

答案:14

 static int ans;
    public static void main(String[] args){
        for(int a=1;a<=9;a++){
            for(int b=1;b<=9;b++){
                if(b==a)continue;
                for(int c=1;c<=9;c++){
                    for(int d=1;d<=9;d++){
                        if(d==c)continue;
                        int g1=gcd(a*c,b*d);
                        int g2=gcd(a*10+c,b*10+d);
                        if((a*c)/g1==(a*10+c)/g2 && (b*d)/g1==(b*10+d)/g2){
                            ans++;
                        }
                    }
                }
            }
        }
        System.out.println(ans);
    }
    //求a,b的最大公约数
    static int gcd(int a,int b){
        if(b==0)return a;
        return gcd(b,a%b);
    }

第七题:扑克序列

A A 2 2 3 3 4 4, 一共4对扑克牌。请你把它们排成一行。
要求:两个A中间有1张牌,两个2之间有2张牌,两个3之间有3张牌,两个4之间有4张牌。

请填写出所有符合要求的排列中,字典序最小的那个。

例如:22AA3344 比 A2A23344 字典序小。当然,它们都不是满足要求的答案。

请通过浏览器提交答案。“A”一定不要用小写字母a,也不要用“1”代替。
字符间一定不要留空格。

答案:2342A3A4

 static char[] a={'A','A','2','2','3','3','4','4'};
    static Set<String> set=new HashSet<>();
    public static void main(String[] args){
        f(0);
        for(String s:set){
            System.out.println(s);
        }
    }
    static void f(int k){
        if(k==8){
            String s=new String(a);
            if(check(s)){
                set.add(s);
            }
        }
        for(int i=k;i<8;i++) {
            char t = a[k];
            a[k] = a[i];
            a[i] = t;
            f(k + 1);
            t = a[k];
            a[k] = a[i];
            a[i] = t;
        }
    }
    static boolean check(String s){
        if(s.lastIndexOf('A')-s.indexOf('A')==2&&
           s.lastIndexOf('2')-s.indexOf('2')==3&&
           s.lastIndexOf('3')-s.indexOf('3')==4&&
           s.lastIndexOf('4')-s.indexOf('4')==5
        )return true;
        return false;
    }

第八题:分糖果

问题描述

有n个小朋友围坐成一圈。老师给每个小朋友随机发偶数个糖果,然后进行下面的游戏:

每个小朋友都把自己的糖果分一半给左手边的孩子。

一轮分糖后,拥有奇数颗糖的孩子由老师补给1个糖果,从而变成偶数。

反复进行这个游戏,直到所有小朋友的糖果数都相同为止。

你的任务是预测在已知的初始糖果情形下,老师一共需要补发多少个糖果。

输入格式

程序首先读入一个整数N(2 < N < 100),表示小朋友的人数。
接着是一行用空格分开的N个偶数(每个偶数不大于1000,不小于2)

输出格式

要求程序输出一个整数,表示老师需要补发的糖果数。

样例输入

3
2 2 4

样例输出

4
分析:
每一轮中:
每个小朋友都把自己的糖果分一半给左手边的孩子。可以遍历数组,从数组的第二个数开始,将自己的一半分给前一个位置的数。

for (int i = 1; i < n; i++) {
                a[i - 1] = a[i - 1] / 2 + a[i] / 2;
}

需要注意的是,要在每一轮的开始,先保存一下a[0]的值,因为最后a[0]要分一半的糖果给a[n-1],如果不保存,那么最后算a[n-1]时,a[0]分给a[n-1]一半的糖果,但是此时的a[0]已经不是最开始的数量了,而是a[1]分一半给a[0]之后的数量。
每一轮每个孩子分完糖果之后就判断一下是否是奇数个糖果,如果是奇数个糖果,那么就再给他补发一个糖果,用ans记录补发给孩子的糖果

static int n;
    static int[] a;
    static int ans;
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        n=sc.nextInt();
        a=new int[n];
        for(int i=0;i<n;i++){
            a[i]=sc.nextInt();
        }
        while(check(a)) {
            int t = a[0];
            for (int i = 1; i < n; i++) {
                a[i - 1] = a[i - 1] / 2 + a[i] / 2;
                if (a[i - 1] % 2 != 0) {
                    a[i - 1] = a[i - 1] + 1;
                    ans++;
                }
            }
            a[n - 1] = a[n - 1] / 2 + t / 2;
            if (a[n - 1] % 2 != 0) {
                a[n - 1] = a[n - 1] + 1;
                ans++;
            }
        }
        System.out.println(ans);
    }
    static boolean check(int[] a){
        int c=a[0];
        for(int i=1;i<n;i++){
            if(a[i]!=c)
                return true;
        }
        return false;
    }

第九题:地宫取宝

X 国王有一个地宫宝库。是 n x m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。

地宫的入口在左上角,出口在右下角。

小明被带到地宫的入口,国王要求他只能向右或向下行走。

走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,
小明就可以拿起它(当然,也可以不拿)。

当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明。

请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝。

【数据格式】

输入一行3个整数,用空格分开:n m k (1<=n,m<=50, 1<=k<=12)

接下来有 n 行数据,每行有 m 个整数 Ci (0<=Ci<=12)代表这个格子上的宝物的价值

要求输出一个整数,表示正好取k个宝贝的行动方案数。该数字可能很大,
输出它对 1000000007 取模的结果。

例如,输入:

2 2 2
1 2
2 1

程序应该输出:

2

再例如,输入:

2 3 2
1 2 3
2 1 5

程序应该输出:

14

解决方案1(简单递归,只能解决一部分问题):
从左上角开始进行递归 每次都有两种选择,向下走或者向右走。
当走到右下角时,判断当前手里的物品数量与k是否相等。如果相等,则将记录结果的ans加一。
要注意的一点是:

if((cnt==k)||(cnt==k-1&&cur>max))

因为当递归到右下角时,右下角的那个位置上的物品还没有取,此时如果小明手里的物品数为k-1,并且这个物品的重量大于小明手里所有物品的重量,那么小明取上这个物品刚好可以满足条件,所以这也算一种情况,不能忽略

static int MOD=1000000007;
	static long ans;
	static int[][] a;
	static int n,m,k;
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		n=sc.nextInt();
		m=sc.nextInt();
		k=sc.nextInt();
		a=new int[n][m];
		
		for(int i=0;i<n;i++) {
			for(int j=0;j<m;j++) {
				a[i][j]=sc.nextInt();
			}
		}
		
		dfs(0,0,-1,0);//第一个价值可能为0,所以当前最大价值设置初始值为-1
		System.out.println(ans);
		
	}
	//max为当前手里的最大值,cnt为手里物品的数量
	static void dfs(int x,int y,int max,int cnt) {
		if(x==n||y==m||cnt>k) {
			return;
		}
		int cur=a[x][y];
		if(x==n-1&&y==m-1) {
			if((cnt==k)||(cnt==k-1&&cur>max)) {
				ans++;
				if(ans>MOD)ans%=MOD;
			}
		}
		if(cur>max) {//当价值大于手里当前的最大值时,可以选择取
			dfs(x+1, y, cur, cnt+1);
			dfs(x, y+1, cur, cnt+1);
		}
		//对于价值较小,或者价值较大但不取
			dfs(x+1, y, max, cnt);
			dfs(x, y+1, max, cnt);
	}

解决方案2(记忆型递归,能解决所有数据):
记忆型递归的思路是:
在递归的基础上,用一个数组来记录当前的状态,
比如当x=1,y=1,max=1,cnt=1这种情况已经计算过了,那么就把这种情况的存入到数组cache当中。
先初始化cache为-1 ,那么当在递归时,就可以先判断当前的情况是否已经计算过。
如果计算过,那么cache[x][y][max][cnt]的值不等于-1
就直接返回cache之前缓存当前状态的值即可,而不必再重复计算这种情况。
简单点来说,比如当前x=1,y=1,sum=1,cnt=1。之前已经计算过此种情况到右下角满足题意的情况有5种,那么当别的递归情况递归到x=1,y=1,sum=1,cnt=1时,直接返回5即可,不用再重复递归。

static int MOD=1000000007; 
	static int[][] a;
	static int n,m,k;
	static long[][][][] chche=new long[51][51][14][14];
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		n=sc.nextInt();
		m=sc.nextInt();
		k=sc.nextInt();
		a=new int[n][m];
		
		for(int i=0;i<n;i++) {
			for(int j=0;j<m;j++) {
				a[i][j]=sc.nextInt();
			}
		}
		for(int i=0;i<51;i++) {
			for(int j=0;j<51;j++) {
				for(int q=0;q<14;q++) {
					for(int w=0;w<14;w++) {
						chche[i][j][q][w]=-1;
					}
				}
			}
		}
		//第一个价值可能为0,所以当前最大价值设置初始值为-1
		long ans=dfs(0,0,-1,0);
		System.out.println(ans);
		
	}
	//max为当前手里的最大值,cnt为手里物品的数量
	
	static long dfs(int x,int y,int max,int cnt) {
	//判断max+1而不是max的原因是因为max初始的时候为-1 如果不加1,会出现越界
		if(chche[x][y][max+1][cnt]!=-1)return chche[x][y][max+1][cnt];
		if(x==n||y==m||cnt>k) return 0;
		int cur=a[x][y];
		long ans=0;
		if(x==n-1&&y==m-1) {
			if((cnt==k)||(cnt==k-1&&cur>max)) {
				return 1;
			}
			return 0;
		}
		if(cur>max) {//当价值大于手里当前的最大值时,可以选择取
			ans=(ans+dfs(x+1, y, cur, cnt+1))%MOD;
			ans=(ans+dfs(x, y+1, cur, cnt+1))%MOD;
		}
		//对于价值较小,或者价值较大但不取
			ans=(ans+dfs(x+1, y, max, cnt))%MOD;
			ans=(ans+dfs(x, y+1, max, cnt))%MOD;
			chche[x][y][max+1][cnt]=ans%MOD;
			return ans;
	}

第十题:矩阵翻硬币

小明先把硬币摆成了一个 n 行 m 列的矩阵。

随后,小明对每一个硬币分别进行一次 Q 操作。

对第x行第y列的硬币进行 Q 操作的定义:将所有第 ix 行,第 jy 列的硬币进行翻转。

其中i和j为任意使操作可行的正整数,行号和列号都是从1开始。

当小明对所有硬币都进行了一次 Q 操作后,他发现了一个奇迹——所有硬币均为正面朝上。

小明想知道最开始有多少枚硬币是反面朝上的。于是,他向他的好朋友小M寻求帮助。

聪明的小M告诉小明,只需要对所有硬币再进行一次Q操作,即可恢复到最开始的状态。
然而小明很懒,不愿意照做。于是小明希望你给出他更好的方法。帮他计算出答案。

【数据格式】

输入数据包含一行,两个正整数 n m,含义见题目描述。
输出一个正整数,表示最开始有多少枚硬币是反面朝上的。

【样例输入】

2 3

【样例输出】

1

【数据规模】

对于10%的数据,n、m <= 10^3;
对于20%的数据,n、m <= 10^7;
对于40%的数据,n、m <= 10^15;
对于10%的数据,n、m <= 10^1000(10的1000次方)。

分析:
求1-N里面有多少个平方数
可以对n开平方取整 比如 9里面有 1 4 9 三个
将所有第 ix 行,第 jy 列的硬币进行翻转
比如i j分别为2 3时 那么4x 3y 4x 6y等等都要进行翻转
现在定位在一个点上
假设现在已经全部进行完Q操作
如果这个点翻了奇数次,就可以判断出此硬币开始为反面
怎么判断这个点为奇数次呢?
可以通过坐标x y,因为只要是遇到x或者是y的真因子为坐标,
那么这个点就要被翻一次,比如说x=9,9的真因子有1,3,9,
遇到这个三个数,这个点都要翻一次
如果这个点的x y的真因子为奇数个
奇数乘以奇数为奇数 即总共被翻的次数为奇数
怎么判断这个点x y的真因子都为奇数个呢?
如果 x y都为平方数 那么真因子为奇数个 比如9的真因子为 1 3 9
12的真因子数为1 2 3 4 6 12
所以到此 这道题就是找出1-x 1-y中平方数和的乘积
就是x所包含的平方数 加上y包含的平方数
(数学知识)n包含的平方数总和为对n开方
比如 16包含 1 4 9 16四个 对16开方就是4 17开方也是4
(数学知识) 一个数开方 如果长度为n 12的长度为2
当n为奇数时,其开方之后长度为n/2 + 1
偶数时,开方之后长度为n
由于题上给的数据很大,可以用BigInteger来做

public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		String s1=sc.next();
		String s2=sc.next();
		System.out.println(sqrt(s1).multiply(sqrt(s2)));		
	}

	private static BigInteger sqrt(String s) {
		int length=s.length();
		int len=0;
		if(length%2==0) {
			len=length/2;
		}else {
			len=length/2+1;
		}
		char[] sArr=new char[len];
		Arrays.fill(sArr, '0');
		BigInteger target=new BigInteger(s);
		for(int pos=0;pos<len;pos++) {
			for(char c='1';c<='9';c++) {
				sArr[pos]=c;  //在pos这个位置试着填入1-9
				BigInteger pow=new BigInteger(String.valueOf(sArr)).pow(2);//平方
				//如果pow比s大
				if(pow.compareTo(target)==1) {
					sArr[pos]-=1;
					break;
				}
			}
		}
		
		return new BigInteger(String.valueOf(sArr));
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值