2016第七届蓝桥杯省赛JAVA A组真题解析(带源码及解析)

蓝桥杯历年真题及解析.

目录:

    • 蓝桥杯历年真题及解析.
      • A:煤球数目(难度:★)
        • 题目:
        • 分析:
        • 代码:
      • B:生日蜡烛(难度:★)
        • 题目:
        • 分析:
        • 代码:
      • C:搭积木(难度:★★)
        • 题目:
        • 分析:
        • 代码:
      • D:分小组(难度:★★)
        • 题目:
        • 分析:
        • 代码:
      • E:抽签(难度:★★★)
        • 题目:
        • 分析:
        • 代码:
      • F:寒假作业(难度:★★★)
        • 题目:
        • 分析:
        • 代码:
      • G:剪邮票(难度:★★★★)
        • 题目:
        • 分析:
        • 代码:
      • H:取球博弈(难度:★★★★★)
        • 题目:
        • 分析:
        • 代码:
      • I:交换瓶子(难度:★★★★)
        • 题目:
        • 分析:
        • 代码:
      • J:压缩变换(难度:★★★★★)
        • 题目:
        • 分析:
        • 代码:
  • 算法交流群

A:煤球数目(难度:★)

题目:

有一堆煤球,堆成三角棱锥形。具体:
第一层放1个,
第二层3个(排列成三角形),
第三层6个(排列成三角形),
第四层10个(排列成三角形),

如果一共有100层,共有多少个煤球?

请填表示煤球总数目的数字。

分析:

模拟计算过程即可
答案=171700

代码:

满分

public class A煤球数目 {
	public static void main(String[] args) {
		int n=100;
		int cur=0;int ans=0;
		for(int i=1;i<=n;i++){
			cur+=i;
			ans+=cur;
		}
		System.out.println(ans);
	}
}

B:生日蜡烛(难度:★)

题目:

某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。

现在算起来,他一共吹熄了236根蜡烛。

请问,他从多少岁开始过生日party的?

请填写他开始过生日party的年龄数。

分析:

从枚举起始过生日的时间,
对拍236,拍到了就是结果。
答案=26

代码:

满分

public class B生日蜡烛 {
    public static void main(String[] args) {
        int ans = 0, temp;
        for (int i = 1; i < 200; i++) {
            temp = 0;
            for (int j = i; j < 200; j++) {
                temp += j;
                if (temp == 236) {
                    ans = i;
                } else if (temp > 236) {
                    break;
                }
            }
        }
        System.out.println(ans);
    }
}

C:搭积木(难度:★★)

题目:

小明最近喜欢搭数字积木,
一共有10块积木,每个积木上有一个数字,0~9。

搭积木规则:
每个积木放到其它两个积木的上面,并且一定比下面的两个积木数字小。
最后搭成4层的金字塔形,必须用完所有的积木。

下面是两种合格的搭法:

0
1 2
3 4 5
6 7 8 9

0
3 1
7 5 2
9 8 6 4

请你计算这样的搭法一共有多少种?

请填表示总数目的数字。

分析:

一共有十个元素,枚举所有的搭积木情况,
符合条件计数加一即可。
枚举完后的计数结果即为答案。
答案=768

代码:

满分

public class C搭积木 {
    public static int[] arr={0,1,2,3,4,5,6,7,8,9};
    public static int ans=0;
    public static boolean check(){
        return arr[0]<arr[1]&&arr[0]<arr[2]&&
                arr[1]<arr[3]&&arr[1]<arr[4]&&
                arr[2]<arr[4]&&arr[2]<arr[5]&&
                arr[3]<arr[6]&&arr[3]<arr[7]&&
                arr[4]<arr[7]&&arr[4]<arr[8]&&
                arr[5]<arr[8]&&arr[5]<arr[9];
    }
    public static void qpl(int k){
        if(k>=arr.length){
            if(check())ans++;
            return ;
        }
        for(int i=k;i<arr.length;i++){
            //交换
            int t=arr[i];arr[i]=arr[k];arr[k]=t;
            //递归
            qpl(k+1);
            //回溯
            t=arr[i];arr[i]=arr[k];arr[k]=t;
        }
    }
    public static void main(String[] args) {
        qpl(0);
        System.out.println(ans);
    }
}

D:分小组(难度:★★)

题目:

9名运动员参加比赛,需要分3组进行预赛。
有哪些分组的方案呢?

我们标记运动员为 A,B,C,… I
下面的程序列出了所有的分组方法。

该程序的正常输出为:
ABC DEF GHI
ABC DEG FHI
ABC DEH FGI
ABC DEI FGH
ABC DFG EHI
ABC DFH EGI
ABC DFI EGH
ABC DGH EFI
ABC DGI EFH
ABC DHI EFG
ABC EFG DHI
ABC EFH DGI
ABC EFI DGH
ABC EGH DFI
ABC EGI DFH
ABC EHI DFG
ABC FGH DEI
ABC FGI DEH
ABC FHI DEG
ABC GHI DEF
ABD CEF GHI
ABD CEG FHI
ABD CEH FGI
ABD CEI FGH
ABD CFG EHI
ABD CFH EGI
ABD CFI EGH
ABD CGH EFI
ABD CGI EFH
ABD CHI EFG
ABD EFG CHI
… (以下省略,总共560行)。

public class A
{
	public static String remain(int[] a)
	{
		String s = "";
		for(int i=0; i<a.length; i++){
			if(a[i] == 0) s += (char)(i+'A');
		}	
		return s;
	}
	
	public static void f(String s, int[] a)
	{
		for(int i=0; i<a.length; i++){
			if(a[i]==1) continue;
			a[i] = 1;
			for(int j=i+1; j<a.length; j++){
				if(a[j]==1) continue;
				a[j]=1;
				for(int k=j+1; k<a.length; k++){
					if(a[k]==1) continue;
					a[k]=1;
					System.out.println(__________________________________);  //填空位置
					a[k]=0;
				}
				a[j]=0;
			}
			a[i] = 0;
		}
	}
	
	public static void main(String[] args)
	{
		int[] a = new int[9];		
		a[0] = 1;
		
		for(int b=1; b<a.length; b++){
			a[b] = 1;
			for(int c=b+1; c<a.length; c++){
				a[c] = 1;
				String s = "A" + (char)(b+'A') + (char)(c+'A');
				f(s,a);
				a[c] = 0;
			}
			a[b] = 0;
		}
	}
}

仔细阅读代码,填写划线部分缺少的内容。

分析:

题目要求分三组,
通过阅读源码,发现main函数内已经完成了第一组的分配,
remain(int a[])完成的是第三组的分配,
而第二组则与f函数内部三层循环的i,j,k,相关

答案=s+" “+(char)(i+‘A’)+(char)(j+‘A’)+(char)(k+‘A’)+” "+remain(a)

代码:

满分

public class D分小组
{
	public static String remain(int[] a)
	{
		String s = "";
		for(int i=0; i<a.length; i++){
			if(a[i] == 0) s += (char)(i+'A');
		}	
		return s;
	}
	
	public static void f(String s, int[] a)
	{
		for(int i=0; i<a.length; i++){
			if(a[i]==1) continue;
			a[i] = 1;
			for(int j=i+1; j<a.length; j++){
				if(a[j]==1) continue;
				a[j]=1;
				for(int k=j+1; k<a.length; k++){
					if(a[k]==1) continue;
					a[k]=1;
//					System.out.println(__________________________________);  //填空位置
					System.out.println(s+(char)(i+'A')+(char)(j+'A')+(char)(k+'A')+remain(a));
					a[k]=0;
				}
				a[j]=0;
			}
			a[i] = 0;
		}
	}
	
	public static void main(String[] args)
	{
		int[] a = new int[9];		
		a[0] = 1;
		
		for(int b=1; b<a.length; b++){
			a[b] = 1;
			for(int c=b+1; c<a.length; c++){
				a[c] = 1;
				String s = "A" + (char)(b+'A') + (char)(c+'A');
				f(s,a);
				a[c] = 0;
			}
			a[b] = 0;
		}
	}
}

E:抽签(难度:★★★)

题目:

X星球要派出一个5人组成的观察团前往W星。
其中:
A国最多可以派出4人。
B国最多可以派出2人。
C国最多可以派出2人。

那么最终派往W星的观察团会有多少种国别的不同组合呢?

下面的程序解决了这个问题。
数组a[] 中既是每个国家可以派出的最多的名额。
程序执行结果为:
DEFFF
CEFFF
CDFFF
CDEFF
CCFFF
CCEFF
CCDFF
CCDEF
BEFFF
BDFFF
BDEFF
BCFFF
BCEFF
BCDFF
BCDEF

(以下省略,总共101行)

public class A
{
	public static void f(int[] a, int k, int n, String s)
	{
		if(k==a.length){ 
			if(n==0) System.out.println(s);
			return;
		}
		
		String s2 = s;
		for(int i=0; i<=a[k]; i++){
			_____________________________;   //填空位置
			s2 += (char)(k+'A');
		}
	}
	
	public static void main(String[] args)
	{
		int[] a = {4,2,2,1,1,3};
		
		f(a,0,5,"");
	}
}

仔细阅读代码,填写划线部分缺少的内容。

分析:

很明显的递归调用问题,
a表示数据数组,不需要改变
每次调用k+1,讨论下一个国家出人数的问题
n-i表示本来差n个人,来了i人之后,还差n-i人
用s2代替之前的s
答案=ans=f(a,k+1,n-i,s2);

代码:

满分

public class E抽签
{
	public static void f(int[] a, int k, int n, String s)
	{
		if(k==a.length){ 
			if(n==0) System.out.println(s);
			return;
		}
		
		String s2 = s;
		for(int i=0; i<=a[k]; i++){
			f(a,k+1,n-i,s2);
//			_____________________________;   //填空位置
			s2 += (char)(k+'A');
		}
	}
	
	public static void main(String[] args)
	{
		int[] a = {4,2,2,1,1,3};
		
		f(a,0,5,"");
	}
}

F:寒假作业(难度:★★★)

题目:

现在小学的数学题目也不是那么好玩的。
看看这个寒假作业:
2016第七届蓝桥杯省赛JAVA A组真题解析(带源码及解析)_第1张图片

每个方块代表1~13中的某一个数字,但不能重复。
比如:
6 + 7 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5

以及:
7 + 6 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5

就算两种解法。(加法,乘法交换律后算不同的方案)

你一共找到了多少种方案?

请填写表示方案数目的整数。

分析:

十二项,全排列问题,
枚举所有的排列进行检查即可,
不过最大的问题是在运算的时候会出现超时的情况。
所以我们需要及时的进行剪枝。
就是多次check即可。
答案=64

代码:

满分

public class F寒假作业 {
    static int ans=0;
    static int arr[]={1,2,3,4,5,6,7,8,9,10,11,12,13};
    static boolean check1(){
        return arr[0]+arr[1]==arr[2];
    }
    static boolean check2(){
        return arr[3]-arr[4]==arr[5];
    }
    static boolean check3(){
        return arr[6]*arr[7]==arr[8];
    }
    static boolean check4(){
        return arr[9]/arr[10]==arr[11]&&arr[9]%arr[10]==0;
    }
    static void qpl(int k){
        if(k>=arr.length){
            if(check4()){
                ans++;
            }
        }else{
            if(k>2&&!check1())return;
            if(k>5&&!check2())return;
            if(k>8&&!check3())return;
            for(int i=k;i<arr.length;i++){
                int t=arr[i];arr[i]=arr[k];arr[k]=t;
                qpl(k+1);
                t=arr[i];arr[i]=arr[k];arr[k]=t;
            }
        }
    }
    public static void main(String[] args) {
        qpl(0);
        System.out.println(ans);
    }
     
}

G:剪邮票(难度:★★★★)

题目:

如图
2016第七届蓝桥杯省赛JAVA A组真题解析(带源码及解析)_第2张图片

有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如下图中,粉红色所示部分就是合格的剪取。
2016第七届蓝桥杯省赛JAVA A组真题解析(带源码及解析)_第3张图片
2016第七届蓝桥杯省赛JAVA A组真题解析(带源码及解析)_第4张图片

请你计算,一共有多少种不同的剪取方法。

请填写表示方案数目的整数。

分析:

我们枚举5个位置,对枚举完的图进行BFS搜索查看是否连通,
如果联通,将其保存到set,最终set的长度即为最终结果
答案=116

代码:

满分

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
 
 
public class G剪邮票 {
    public static int sz[]=new int[5];
    public static char map[][]={
        {'a','b','c','d'},
        {'e','f','g','h'},
        {'i','j','k','l'}
    };
    public static int maxn=12,count=0;
    public static HashSet<String> ans=new HashSet<String>();
    public static void check(){
        ArrayList<Integer> now=new ArrayList<Integer>();
        ArrayList<Integer> old=new ArrayList<Integer>();
        now.add(sz[0]);
        int p=0;
        while(p<5){
            p++;
            for(int t:now){
                for(int i=0;i<sz.length;i++){
                    if(sz[i]+4==t||sz[i]-4==t||(sz[i]-1==t&&sz[i]%4>t%4)||(sz[i]+1==t&&sz[i]%4<t%4)){
                        old.add(sz[i]);
                    }
                }
            }
            now.addAll(old);
            old.clear();
        }
        HashSet<Integer> mid=new HashSet<Integer>();
        for(int t:now){
            mid.add(t);
        }
        if(mid.size()<5)return ;
        Arrays.sort(sz);
        ans.add((char)('a'+sz[0])+""+(char)('a'+sz[1])+""+(char)('a'+sz[2])+""+(char)('a'+sz[3])+""+(char)('a'+sz[4]));
    }
    public static void main(String[] args) {
        boolean buf[]=new boolean [maxn];
        for(int i=0;i<maxn;i++){
            sz[0]=i;
            buf[sz[0]]=true;
            for(sz[1]=sz[0]+1;sz[1]<maxn;sz[1]++){
                buf[sz[1]]=true;
                for(sz[2]=sz[1]+1;sz[2]<maxn;sz[2]++){
                    buf[sz[2]]=true;
                    for(sz[3]=sz[2]+1;sz[3]<maxn;sz[3]++){
                        buf[sz[3]]=true;
                        for(sz[4]=sz[3]+1;sz[4]<maxn;sz[4]++){
                            buf[sz[4]]=true;
                            check();
                            buf[sz[4]]=false;
                        }
                        buf[sz[3]]=false;
                    }
                    buf[sz[2]]=false;
                }
                buf[sz[1]]=false;
            }
            buf[sz[0]]=false;
        }
        System.out.println(ans.size());
    }
}

H:取球博弈(难度:★★★★★)

题目:

两个人玩取球的游戏。
一共有N个球,每人轮流取球,每次可取集合{n1,n2,n3}中的任何一个数目。
如果无法继续取球,则游戏结束。
此时,持有奇数个球的一方获胜。
如果两人都是奇数,则为平局。

假设双方都采用最聪明的取法,
第一个取球的人一定能赢吗?
试编程解决这个问题。

输入格式:
第一行3个正整数n1 n2 n3,空格分开,表示每次可取的数目 (0 第二行5个正整数x1 x2 … x5,空格分开,表示5局的初始球数(0

输出格式:
一行5个字符,空格分开。分别表示每局先取球的人能否获胜。
能获胜则输出+,
次之,如有办法逼平对手,输出0,
无论如何都会输,则输出-

例如,输入:
1 2 3
1 2 3 4 5

程序应该输出:
+ 0 + 0 -

再例如,输入:
1 4 5
10 11 12 13 15

程序应该输出:
0 - 0 + +

再例如,输入:
2 3 5
7 8 9 10 11

程序应该输出:
+ 0 0 0 0
分析:

题目分析.

代码:

题目分析.

I:交换瓶子(难度:★★★★)

题目:

有N个瓶子,编号 1 ~ N,放在架子上。

比如有5个瓶子:
2 1 3 5 4

要求每次拿起2个瓶子,交换它们的位置。
经过若干次后,使得瓶子的序号为:
1 2 3 4 5

对于这么简单的情况,显然,至少需要交换2次就可以复位。

如果瓶子更多呢?你可以通过编程来解决。

输入格式为两行:
第一行: 一个正整数N(N<10000), 表示瓶子的数目
第二行:N个正整数,用空格分开,表示瓶子目前的排列情况。

输出数据为一行一个正整数,表示至少交换多少次,才能完成排序。

例如,输入:
5
3 1 2 5 4

程序应该输出:
3

再例如,输入:
5
5 4 3 2 1

程序应该输出:
2

分析:

记录每个瓶子所在位置,
从头到尾进行运算,每次运算把该数字送到他该去的地方,把占他位置的元素取出来,循环操作,运算到末尾即结束。

代码:

在这里插入图片描述


import java.util.Scanner;
 
public class I交换瓶子 {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        while(sc.hasNext()){
            int n=sc.nextInt();
            int arr[]=new int[n];
            int index[]=new int[n+1];
            for(int i=0;i<n;i++){
                arr[i]=sc.nextInt();
                index[arr[i]]=i;
            }
            long ans=0;
            for(int i=0;i<n;i++){
                if(arr[i]!=i+1){
                    ans++;
                    int idx=index[i+1];
                    arr[idx]=arr[i];
                    arr[i]=i+1;
                    index[arr[i]]=i;
                    index[arr[idx]]=idx;
                }
            }
//          System.out.println(Arrays.toString(index));
            System.out.println(ans);
        }
    }
}

J:压缩变换(难度:★★★★★)

题目:

小明最近在研究压缩算法。
他知道,压缩的时候如果能够使得数值很小,就能通过熵编码得到较高的压缩比。
然而,要使数值很小是一个挑战。

最近,小明需要压缩一些正整数的序列,这些序列的特点是,后面出现的数字很大可能是刚出现过不久的数字。对于这种特殊的序列,小明准备对序列做一个变换来减小数字的值。

变换的过程如下:
从左到右枚举序列,每枚举到一个数字,如果这个数字没有出现过,刚将数字变换成它的相反数,如果数字出现过,则看它在原序列中最后的一次出现后面(且在当前数前面)出现了几种数字,用这个种类数替换原来的数字。

比如,序列(a1, a2, a3, a4, a5)=(1, 2, 2, 1, 2)在变换过程为:
a1: 1未出现过,所以a1变为-1;
a2: 2未出现过,所以a2变为-2;
a3: 2出现过,最后一次为原序列的a2,在a2后、a3前有0种数字,所以a3变为0;
a4: 1出现过,最后一次为原序列的a1,在a1后、a4前有1种数字,所以a4变为1;
a5: 2出现过,最后一次为原序列的a3,在a3后、a5前有1种数字,所以a5变为1。
现在,给出原序列,请问,按这种变换规则变换后的序列是什么。

输入格式:
输入第一行包含一个整数n,表示序列的长度。
第二行包含n个正整数,表示输入序列。

输出格式:
输出一行,包含n个数,表示变换后的序列。

例如,输入:
5
1 2 2 1 2

程序应该输出:
-1 -2 0 1 1

再例如,输入:
12
1 1 2 3 2 3 1 2 2 2 3 1

程序应该输出:
-1 0 -2 -3 1 1 2 2 0 0 2 2

数据规模与约定
对于30%的数据,n<=1000;
对于50%的数据,n<=30000;
对于100%的数据,1 <=n<=100000,1<=ai<=10^9

分析:

线段树。

代码:

在这里插入图片描述

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
 
 
public class J压缩变换 {
 
    public static int n,m;
    public static int[] res,segTree;
    public static Map<Integer, Integer> map = new HashMap<Integer, Integer>();
 
    public static void init(int n_){
        m = 1;
        while(m<n_) m <<= 1;
        //for(int i=0;i
        Arrays.fill(segTree, 0);
    }
 
    public static void update(int k,int v){
        k += m-1;
        if(v==1) segTree[k]++;
        else segTree[k]--;
        while(k>0){
            k = (k-1)/2;
            if(v==1) segTree[k]++;
            else segTree[k]--;
        }
    }
 
    public static int query(int a,int b,int k,int l,int r){
        if(a<=l&&r<=b) return segTree[k];
        else if(l>=b||r<=a) return 0;
        else{
            int m = l + (r-l)/2;
            int left = query(a, b, k*2+1, l, m);
            int right = query(a, b, k*2+2, m, r);
            return left + right;
        }
    }
 
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);
        while(in.hasNext()){
            n = in.nextInt();
            segTree = new int[4*n];
            res = new int[n+10];
            map.clear();
            init(n);
            int t,last=-1;
            for(int i=0;i<n;i++){
                t = in.nextInt();
                if(!map.containsKey(t)){
                    res[i] = -t;
                    map.put(t, i);
                    update(i, 1);
                }
                else{
                    last = map.get(t);
                    res[i] = query(last+1,i,0,0,m);
                    update(last, 0);
                    map.put(t, i);
                    update(i, 1);
                }
            }
            for(int i=0;i<n;i++) System.out.print(res[i]+" ");
            System.out.println();
        }
    }
 
}

算法交流群

2016第七届蓝桥杯省赛JAVA A组真题解析(带源码及解析)_第5张图片

你可能感兴趣的:(蓝桥杯,蓝桥杯,JAVA,A组,第七届蓝桥杯,2016蓝桥杯A组,蓝桥真题)