蓝桥杯2013-2016真题

javaB组蓝桥杯省赛历年真题(23-16)

历年真题

第一次蓝桥杯百校真题大联赛

  • 大量模拟题,提高编码速度
  • 基本数据结构:队列、栈、二叉树
  • 排序、排列
  • DFS、BFS
  • 简单数学:GCD、快速幂、素数
  • 简单字符串
  • 线性DP
  • 简单图论:最短路、最小生成树

尺取法

概念

双指针,把两种循环转换为一重循环,从而把复杂度从O (n^2)提高到O(n)

image-20220310153045398

反向扫描

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9FCmjrOG-1651583579165)(https://gitee.com/cl2854697833/my-picture/raw/master/img/202204022221266.png)]

同向扫描

image-20220310153756038

真题

image-20220310154053553

image-20220310154334488

image-20220310154437312

快慢指针

image-20220310154829045

image-20220310155029128

image-20220310160232455

image-20220310160805502

2013年真题

一、世纪末的星期

标题: 世纪末的星期

曾有邪教称1999年12月31日是世界末日。当然该谣言已经不攻自破。
还有人称今后的某个世纪末的12月31日,如果是星期一则会....
有趣的是,任何一个世纪末的年份的12月31日都不可能是星期一!!
于是,“谣言制造商”又修改为星期日......
1999年的12月31日是星期五,请问:未来哪一个离我们最近的一个世纪末年(即xx99年)的12月31日正好是星期天(即星期日)?
请回答该年份(只写这个4位整数,不要写12月31等多余信息)

解题思路:

先选择2099(不同的年1999+100)年在选择12月31日,查看其星期,使用calendar类

package _2013;

import java.util.Calendar;

public class _世纪末的星期 {

	public static void main(String[] args) {
	//创建Calendar的实例
	Calendar calendar=Calendar.getInstance();
	for(int i=1999;i<=10000;i=i+100) {//循环,每次+100年
		calendar.set(calendar.YEAR, i);//set方法,两个参数(设置的项,甚至的值)
		calendar.set(calendar.MONTH, 11);//从0开始记数,1月=0,12月=11
		calendar.set(calendar.DAY_OF_MONTH, 31);//设置日期,31号
		System.out.println(i+" "+calendar.get(calendar.DAY_OF_WEEK));//验证1999年12月31日 星期五 是不是 6
		if (calendar.get(calendar.DAY_OF_WEEK)==1) {//get方法获取值,day_of_week一周中的第几天,1代表星期天
			System.out.println(i);
			break;
		}
		
	}
	
}
}

二、马虎的算式

标题: 马虎的算式

小明是个急性子,上小学的时候经常把老师写在黑板上的题目抄错了。

有一次,老师出的题目是:36 x 495 = ?

他却给抄成了:396 x 45 = ?

但结果却很戏剧性,他的答案竟然是对的!!

因为 36 * 495 = 396 * 45 = 17820

类似这样的巧合情况可能还有很多,比如:27 * 594 = 297 * 54

假设 a b c d e 代表1~9不同的5个数字(注意是各不相同的数字,且不含0)

能满足形如: ab * cde = adb * ce 这样的算式一共有多少种呢?

请你利用计算机的优势寻找所有的可能,并回答不同算式的种类数。

满足乘法交换律的算式计为不同的种类,所以答案肯定是个偶数。

答案直接通过浏览器提交。
注意:只提交一个表示最终统计种类数的数字,不要提交解答过程或其它多余的内容。

package _2013;

public class _马虎的算式 {
	
public static void main(String[] args) {
	int num=0;
	for(int a=1;a<=9;a++) {
		for(int b=1;b<=9;b++) {
			for(int c=1;c<=9;c++) {
				for(int d=1;d<=9;d++) {
					for(int e=1;e<=9;e++) {
						if ((a*10+b)*(c*100+d*10+e)==((a*100+d*10+b)*(c*10+e))) {
							if(a!=b&&a!=c&&a!=d&&a!=e&&b!=c&&b!=d&&b!=e&&c!=d&&c!=e&&d!=e) {
								num++;
							}						
						}
					}
				}
			}
		}
	}
	System.out.println(num);
	//纯纯暴力
}
}

三、振兴中华

标题: 振兴中华

小明参加了学校的趣味运动会,其中的一个项目是:跳格子。
地上画着一些格子,每个格子里写一个字,如下所示:(也可参见p1.jpg)
从我做起振
我做起振兴
做起振兴中
起振兴中华

比赛时,先站在左上角的写着“从”字的格子里,可以横向或纵向跳到相邻的格子里,但不能跳到对角的格子或其它位置。一直要跳到“华”字结束。
要求跳过的路线刚好构成“从我做起振兴中华”这句话。
请你帮助小明算一算他一共有多少种可能的跳跃路线呢?
答案是一个整数,请通过浏览器直接提交该数字。
注意:不要提交解答过程,或其它辅助说明类的内容。

 从我做起振        (0, 0)    (0, 1)    (0, 2)    (0, 3)    (0, 4)
 我做起振兴        (1, 0)    (1, 1)    (1, 2)    (1, 3)    (1, 4)
 做起振兴中        (2, 0)    (2, 1)    (2, 2)    (2, 3)    (2, 4)
 起振兴中华        (3, 0)    (3, 1)    (3, 2)    (3, 3)    (3, 4)

img

package _2013;

public class _3振兴中华 {
//从左上角走到右下角,要求一共有多三种走法	
	public  static void  main(String[] args) {
	int num=0;
	num=dfs(0, 0);
	System.out.println(num);
	}
    //首先使用递归,分成两类,一个一开始向下走,一个一开始向右走,分别计算这两种走法最后的总数。~
public static int dfs(int i,int j) {
	//终止条件
	if (i==3||j==4) {//i=3表示向下走到了头,没有方法了,j同理
		return 1;
	}
	return dfs(i+1, j)+dfs(i, j+1);
}
}

四、黄金连分数

标题: 黄金连分数

黄金分割数0.61803… 是个无理数,这个常数十分重要,在许多工程问题中会出现。有时需要把这个数字求得很精确。

对于某些精密工程,常数的精度很重要。也许你听说过哈勃太空望远镜,它首次升空后就发现了一处人工加工错误,对那样一个庞然大物,其实只是镜面加工时有比头发丝还细许多倍的一处错误而已,却使它成了“近视眼”!!

言归正传,我们如何求得黄金分割数的尽可能精确的值呢?有许多方法。

比较简单的一种是用连分数:

黄金数 = ---------------------
1
1 + -----------------
1
1 + -------------
1
1 + ---------
1 + …

这个连分数计算的“层数”越多,它的值越接近黄金分割数。

请你利用这一特性,求出黄金分割数的足够精确值,要求四舍五入到小数点后100位。

小数点后3位的值为:0.618
小数点后4位的值为:0.6180
小数点后5位的值为:0.61803
小数点后7位的值为:0.6180340
(注意尾部的0,不能忽略)

你的任务是:写出精确到小数点后100位精度的黄金分割值。

注意:尾数的四舍五入! 尾数是0也要保留!

显然答案是一个小数,其小数点后有100位数字,请通过浏览器直接提交该数字。
注意:不要提交解答过程,或其它辅助说明类的内容。

是斐波那契之比,关键是选择哪两个之比,因为要求小数点之后100位,所以尽量精确

可以选择一个很大的数先算一下,然后更新再算一下,若后100位没啥大的变化,则可以。

package com.lanqiao;

import java.math.BigDecimal;

public class demo2 {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
//        BigDecimal a=new BigDecimal(fbnq(35));
//        BigDecimal b=new BigDecimal(fbnq(36));
        //递归时间太长了
        BigDecimal a=BigDecimal.ONE;
        BigDecimal b=BigDecimal.ONE;
        for (int i=3;i<=500;i++){
            BigDecimal t=b;
            b=a.add(b);
            a=t;
        }
        BigDecimal c=a.divide(b, 100,BigDecimal.ROUND_HALF_DOWN);
        System.out.println(c);
//0.6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911375
//0.6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911375
    }

    public static int fbnq(int n) {
        int a=1;
        int b=1;
        if (n<2) {
            return 1;
        }

        return fbnq(n-1)+fbnq(n-2);
    }
}

五、有理数类

标题:有理数类

有理数就是可以表示为两个整数的比值的数字。一般情况下,我们用近似的小数表示。但有些时候,不允许出现误差,必须用两个整数来表示一个有理数。

这时,我们可以建立一个“有理数类”,下面的代码初步实现了这个目标。为了简明,它只提供了加法和乘法运算。
class Rational
{undefined
private long ra;
private long rb;
private long gcd(long a, long b){undefined
if(b= =0) return a;
return gcd(b,a%b);
}
public Rational(long a, long b){undefined
ra = a;
rb = b;
long k = gcd(ra,rb);
if(k>1){ //需要约分
ra /= k;
rb /= k;
}
}
// 加法
public Rational add(Rational x){undefined
return ________________________________________; //填空位置
}
// 乘法
public Rational mul(Rational x){undefined
return new Rational(rax.ra, rbx.rb);
}
public String toString(){undefined
if(rb==1) return “” + ra;
return ra + “/” + rb;
}
}

使用该类的示例:
Rational a = new Rational(1,3);
Rational b = new Rational(1,6);
Rational c = a.add(b);
System.out.println(a + “+” + b + “=” + c);

请分析代码逻辑,并推测划线处的代码,通过网页提交
注意:仅把缺少的代码作为答案,千万不要填写多余的代码、符号或说明文字

    public Rational add(Rational x){
        return new Rational(this.ra*x.rb + this.rb*x.ra, this.rb*x.rb);  //填空位置
        //  一定返回Rational  所以, 先new一个Rational
        //  分母:分母*分母:this.rb*x.rb
        //  分子:自己的分子*x的分母+自己的分母*x的分子
    }

六、三部排序

标题:三部排序

一般的排序有许多经典算法,如快速排序、希尔排序等。

但实际应用时,经常会或多或少有一些特殊的要求。我们没必要套用那些经典算法,可以根据实际情况建立更好的解法。

比如,对一个整型数组中的数字进行分类排序:

使得负数都靠左端,正数都靠右端,0在中部。注意问题的特点是:负数区域和正数区域内并不要求有序。可以利用这个特点通过1次线性扫描就结束战斗!!

以下的程序实现了该目标。

static void sort(int[] x)
{undefined
    int p = 0;
    int left = 0;
    int right = x.length-1;

    while(p<=right){undefined
        if(x[p]<0){undefined
            int t = x[left];
            x[left] = x[p];
            x[p] = t;
            left++;
            p++;
        }
        else if(x[p]>0){undefined
            int t = x[right];
            x[right] = x[p];
            x[p] = t;
            right--;
        }
        else{undefined
            _________________________;  //代码填空位置
        }
    }
}
   如果给定数组:
   25,18,-2,0,16,-5,33,21,0,19,-16,25,-3,0
   则排序后为:
   -3,-2,-16,-5,0,0,0,21,19,33,25,16,18,25

请分析代码逻辑,并推测划线处的代码,通过网页提交
注意:仅把缺少的代码作为答案,千万不要填写多余的代码、符号或说明文字!!

p++

分析:其实主要就是进行几个判断,当x[p]小于0时,就和x[left]进行替换,当x[p]>0时,就和x[right]进行替换,x[p]=0时,不换,p++,继续下一个。

七、错误票据

标题:错误票据

某涉密单位下发了某种票据,并要在年终全部收回。

每张票据有唯一的ID号。全年所有票据的ID号是连续的,但ID的开始数码是随机选定的。

因为工作人员疏忽,在录入ID号的时候发生了一处错误,造成了某个ID断号,另外一个ID重号。

你的任务是通过编程,找出断号的ID和重号的ID。

假设断号不可能发生在最大和最小号。
要求程序首先输入一个整数N(N<100)表示后面数据行数。
接着读入N行数据。
每行数据长度不等,是用空格分开的若干个(不大于100个)正整数(不大于100000)
每个整数代表一个ID号。

要求程序输出1行,含两个整数m n,用空格分隔。
其中,m表示断号ID,n表示重号ID

例如:
用户输入:
2
5 6 8 11 9
10 12 9

则程序输出:
7 9
再例如:
用户输入:
6
164 178 108 109 180 155 141 159 104 182 179 118 137 184 115 124 125 129 168 196
172 189 127 107 112 192 103 131 133 169 158
128 102 110 148 139 157 140 195 197
185 152 135 106 123 173 122 136 174 191 145 116 151 143 175 120 161 134 162 190
149 138 142 146 199 126 165 156 153 193 144 166 170 121 171 132 101 194 187 188
113 130 176 154 177 120 117 150 114 183 186 181 100 163 160 167 147 198 111 119

则程序输出:
105 120
资源约定:
峰值内存消耗(含虚拟机) < 64M
CPU消耗  < 2000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.6及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
package q2013;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;

public class A07_错误票据 {
    //input :   N(表示输入的行数)    data(接着输入N行数据)
    //output:m,n  断号ID、重号ID
    public static void main(String[] args) {
        //1、想要接收数据
        /*
        总共有n行数据,
         */
        Scanner sc=new Scanner(System.in);
        int N=sc.nextInt();
        sc.nextLine();//吃掉整数后面的换行符
        //创建一个可扩容的数组
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < N; i++) {
            String line=sc.nextLine();//读取下一行数据
            String[] split = line.split(" ");//将这字符串转化为字符数组
            for (int j = 0; j < split.length; j++) {
                list.add(Integer.parseInt(split[j]));//将字符串转换为int类型的整数
                }
        }
        //2、对数据进行处理
        Collections.sort(list);//对数组进行排序,原地替换?
        int breakNum=0  ,repeatedNum=0;
        for (int j = 1; j < list.size(); j++) {
            if (list.get(j)-list.get(j-1)==2){//arraylist不能直接[],要用.get方法
                breakNum=list.get(j)-1;
            }
            //注意!!!!
            //list.get(j)-list.get(j-1)==2不严谨,
            //==,表示地址,equals()表示内容

            if (list.get(j).equals(list.get(j-1))){
                repeatedNum=list.get(j);
            }
        }
        System.out.println(breakNum+" "+repeatedNum);
    }
    //arraylist方法
    /*

     */
}

八、幸运数?

标题:幸运数

    幸运数是波兰数学家乌拉姆命名的。它采用与生成素数类似的“筛法”生成。

    首先从1开始写出自然数1,2,3,4,5,6,....

    1 就是第一个幸运数。
    我们从2这个数开始。把所有序号能被2整除的项删除,变为:

    1 _ 3 _ 5 _ 7 _ 9 ....

    把它们缩紧,重新记序,为:

    1 3 5 7 9 .... 。这时,3为第2个幸运数,然后把所有能被3整除的序号位置的数删去。
    注意,是序号位置,不是那个数本身能否被3整除!! 删除的应该是5,11, 17, ...

    此时7为第3个幸运数,然后再删去序号位置能被7整除的(19,39,...)

    最后剩下的序列类似:

    1, 3, 7, 9, 13, 15, 21, 25, 31, 33, 37, 43, 49, 51, 63, 67, 69, 73, 75, 79, ...

本题要求:

输入两个正整数m n, 用空格分开 (m < n < 1000*1000)
程序输出 位于m和n之间的幸运数的个数(不包含m和n)。

例如:
用户输入:
1 20
程序输出:
5

例如:
用户输入:
30 69
程序输出:
8

资源约定:
峰值内存消耗(含虚拟机) < 64M
CPU消耗  < 2000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.6及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
package q2013;

import java.util.Scanner;

public class Q8幸运数 {

    public static void main(String[] args) {//枚举、记数、模拟`筛选`过程!!
        Scanner sc=new Scanner(System.in);
        int m=sc.nextInt();//接受第一个参数
        int n=sc.nextInt();//接受第二个参数
        int[] a=new int[n];//存储数据的数组
        //从题目中可以得知第一轮其实已经删除了二的倍数的数据
        for (int i = 0; i < n; i++) {
            a[i]=2*i+1;
        }
        int l=1;//幸运数的下标,a[l]是幸运数
        while (true){
            //挪一挪
            int p=l+1;//数字向前移动的坑位
            for (int i=l+1;i<n;i++){//从l位置开始,筛选
                if ((i+1)%a[l]==0){
                }else {
                    a[p]=a[i];
                    p++;
                }
                if (a[p]>n){//算法优化
                    break;//当a[i]>n,break;只要n之前的数据
                }
            }
            l++;
            if (a[l]>=n){//运行到最后一个位置
                break;
            }
        }
        int ans=0;//计算数组中的元素的个数
        for(int i=0;i<n;i++){
            if (a[i]>=n){//超过最大数,即停止计算
                break;
            }
            if (a[i]>m){
                ans++;
            }
        }
        System.out.println(ans);
    }
}

九、带分数?(回溯)

B组第9题

标题:带分数

100 可以表示为带分数的形式:100 = 3 + 69258 / 714

还可以表示为:100 = 82 + 3546 / 197

注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。

类似这样的带分数,100 有 11 种表示法。

题目要求:
从标准输入读入一个正整数N (N<1000*1000)
程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
注意:不要求输出每个表示,只统计有多少表示法!

例如:
用户输入:
100
程序输出:
11

再例如:
用户输入:
105
程序输出:
6

资源约定:
峰值内存消耗(含虚拟机) < 64M
CPU消耗 < 3000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.6及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

package q2013;

import java.util.Scanner;

public class Q09_带分数 {
    static int ans; // 全局变量
    private static int N;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        N = sc.nextInt();
        int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        // int[] arr = {1, 2, 3};
        f(arr, 0); // 全排列函数
        System.out.println(ans);
    }

    // 确认某一个排列的第k位
    private static void f(int[] arr, int k) { // 全排列递归框架
        if (k == 9) { // 全部确认
            check(arr); // 具体功能区
            // print(arr); // sout(数组所有元素);
            return;
        }
        // 选定第k位,
        for (int i = k; i < arr.length; i++) {
            // 将第i位和第k位交换
            int t = arr[i];
            arr[i] = arr[k];
            arr[k] = t;

            // 移交下一层, 确认第k+1位
            f(arr, k + 1);

            // 回溯(换回来) 不影响以后的取值
            // 每一次计算, 都用初始值,不影响后续计算
            t = arr[i];
            arr[i] = arr[k];
            arr[k] = t;
        }
    }

// private static void print(int[] arr) {
//    for (int i = 0; i < arr.length; i++) {
//       System.out.print(arr[i]);
//    }
//    System.out.println();
// }

    // 枚举加号和除号的位置
    private static void check(int[] arr) {
        // +前的字符数最多是7
        for (int i = 1; i <= 7; i++) {
            int num1 = toInt(arr, 0, i); // +前面的一段整数
            if (num1 >= N)
                continue; // 如果此时+号前的数值已经超过了N,没必要验算了
            // /前面的字符数
            for (int j = 1; j <= 8 - i; j++) {
                int num2 = toInt(arr, i, j);
                int num3 = toInt(arr, i + j, 9 - i - j);
                if (num2 % num3 == 0 && num1 + num2 / num3 == N) {
                    ans++;
                }
            }
        }
    }

    /**
     * 数组转整数:1、parseInt();2、toInt()性能更快一些
     *
     * @param arr
     * @param pos:开始计算的位置
     * @param len:计算的长度(计算len次)   计算区间: [pos, pos + len -1]
     * @return
     */
    private static int toInt(int[] arr, int pos, int len) {
        int t = 1;
        int ans = 0;
        for (int i = pos + len - 1; i >= pos; i--) {
            ans += arr[i] * t;
            t *= 10;
        }
        return ans;
    }
}

十、连号区间数

标题:连号区间数(同C语言B组第10题)

小明这些天一直在思考这样一个奇怪而有趣的问题:

在1~N的某个全排列中有多少个连号区间呢?这里所说的连号区间的定义是:

如果区间[L, R] 里的所有元素(即此排列的第L个到第R个元素)递增排序后能得到一个长度为R-L+1的“连续”数列,则称这个区间连号区间。

当N很小的时候,小明可以很快地算出答案,但是当N变大的时候,问题就不是那么简单了,现在小明需要你的帮助。

输入格式:
第一行是一个正整数N (1 <= N <= 50000), 表示全排列的规模。
第二行是N个不同的数字Pi(1 <= Pi <= N), 表示这N个数字的某一全排列。

输出格式:
输出一个整数,表示不同连号区间的数目。

示例:
用户输入:
4
3 2 4 1

程序应输出:
7

用户输入:
5
3 4 2 5 1

程序应输出:
9

解释:
第一个用例中,有7个连号区间分别是:[1,1], [1,2], [1,3], [1,4], [2,2], [3,3], [4,4]
第二个用例中,有9个连号区间分别是:[1,1], [1,2], [1,3], [1,4], [1,5], [2,2], [3,3], [4,4], [5,5]

资源约定:
峰值内存消耗(含虚拟机) < 64M
CPU消耗 < 5000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.6及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

package provincialGames_04_2013;
 
import java.util.Scanner;
 
public class A10_连号区间数 {  //穷举、遍历、扫描
 
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int[] arr = new int[n + 1];
		for (int i = 1; i <= n ; i++) {
			arr[i] = sc.nextInt();
		}
		int ans = 0;
		for (int i = 1; i <=n ; i++) {
			int max = arr[i];
			int min = arr[i];
			for (int j = i; j <= n ; j++) { // ]的位置
				if (arr[j] > max) {
					max = arr[j];
				}
		        if (arr[j] < min) {
		        	min = arr[j];
		        }
		        
		        // j 只能 >= i
		        if (i == j){
		        	// System.out.printf("[%d,%d]\n",i,j);
		        	ans++;
		        } else{ //i<j,判断[i,j]是连号区间
		        	if (max - min == j - i){
		        		// System.out.printf("[%d,%d]\n",i,j);
		        		ans++;
		        	}
		        }
			}
		}
		System.out.println(ans);
	}
}

小结

01 世纪末的星期 枚举每个世纪末,判断是否星期天 Calendar
02 马虎的算式 枚举每个位上的数字,组合判断
03 振兴中华 找重复中的变化,找边界
04 黄金连分数 1.识别问题等价于斐波那契的n项和n+1项的比值,2.n要多少才够,3.怎么处理很大的数和精度要求很高的浮点数

05 有理数类 面向对象+分数加法(通分与约分)
06 三部排序 快速排序(三指针区间法)变体;极限思维(考虑全部是0)

07 错误票据 输入比较特殊,排序,迭代(获取断号和重号),输出
08 幸运数 模拟筛选过程,枚举计数
09 带分数 1-9用递归做全排列,对每一个排列,都枚举+和/的位置,然后进行检查
10 连号区间数 枚举所有区间,检查这个区间里面的数排序后是否连号

2014年真题

一、武功秘籍

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

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

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

7

二、切面条

标题:切面条

一根高筋拉面,中间切一刀,可以得到2根面条。

如果先对折1次,中间切一刀,可以得到3根面条。

如果连续对折2次,中间切一刀,可以得到5根面条。

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

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

本质是找规律

1 1+2^0

3 1+2^1

5 1+2^2

9 1+2^3

三、猜字母

标题:猜字母

把abcd…s共19个字母组成的序列重复拼接106次,得到长度为2014的串。

接下来删除第1个字母(即开头的字母a),以及第3个,第5个等所有奇数位置的字母。

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

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

package Q2014.chen;

import java.util.ArrayList;
import java.util.List;

public class q3 {
    public  static  void q3(){
//        List<Character> strings = new ArrayList<Character>();

        char[] strings=new char[2014];


        int index=0;
        for (int i = 0; i < 106; i++) {
            for (int j = 0; j <19; j++){
                strings[index++]= (char) ('a'+j);
            }
        }

        int len=2014;
        while (len!=1){
            int k=0;
            for (int i = 1; i < len; i+=2) {
                strings[k++]=strings[i];
//                strings.set(strings.get(k++),strings.get(i));
            }
            len=k;
        }
        System.out.println(strings[0]);
//        System.out.println(strings.get(0));

    }

    public static void main(String[] args) {
        q3();
    }
}

四、大衍数列

标题:大衍数列

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

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

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

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

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

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

i%2==0

五、圆周率

标题:圆周率

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

图1中所示,就是一种用连分数的形式表示的圆周率求法。

img

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

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

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

System.out.println(String.format(“%.4f”, (x-1)/4));

小贴士:

在遇到这类的填空题时,我们可以从边界条件开始,取极限值,如n=0,n=1,看看我们的取值,仔细,细心即可

六、奇怪的分式

标题:奇怪的分式

上小学的时候,小明经常自己发明新算法。一次,老师出的题目是:

1/4 乘以 8/5

小明居然把分子拼接在一起,分母拼接在一起,答案是:18/45 (参见图1.png)

img

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

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

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

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

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

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

package Q2014.chen;

public class q6 {
    public static  void  test(){
        //a/b*c/d==?
        /*
        a b c d 分别代表不同的分子分母 从1-9,相同的分子分母不算
         */
        int num=0;
        for (int i = 1; i <=9; i++) {
            for (int j = 1; j <=9 ; j++) {
                if (i==j){
                    continue;
                }
                for (int k = 1; k <= 9; k++) {
                    for (int l = 1; l <= 9; l++) {
                        if (k == l) {
                            continue;
                        }
//                        ((i/j)*(k/l)==((i*10+k)/(j*10)+l))
                        //((i*k)/(j*l))==(i*10+k)/(j*10+l)
                        //为什么不能简答的算除
                        int gcc1 = gcc(i * j, k * l);//求最大公约数
                        int gcc2 = gcc(i * 10 + k, j * 10 + l);
                        if ((i*j/gcc1==(i*10+k)/gcc2)&&(j*l/gcc1==(j*10+l)/gcc2)){
                            System.out.printf("%d,%d,%d,%d\n",i,j,k,l);
                            num++;
                        }
                    }
                }
            }
        }
        System.out.println(num);
    }
    public static int   gcc(int a, int b){
        if (b==0){
            return a;
        }
        return gcc(b,a%b);
    }

    public static void main(String[] args) {
        test();
    }
}

七、扑克排序(全排列)

标题:扑克序列

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

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

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

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

在全排列的基础上,筛选出符合条件的数据,本题难点主要在全排列筛选条件

package Q2014.chen;

import java.util.HashSet;
import java.util.Set;

public class _七扑克排序 {
    /*
     A 2 2 3 3 4 4, 一共4对扑克牌。请你把它们排成一行。
要求:两个A中间有1张牌,两个2之间有2张牌,两个3之间有3张牌,两个4之间有4张牌。
请填写出所有符合要求的排列中,字典序最小的那个。
例如:22AA3344 比 A2A23344 字典序小。当然,它们都不是满足要求的答案。
请通过浏览器提交答案。“A”一定不要用小写字母a,也不要用“1”代替。字符间一定不要留空格。
     */

    //解法:全排列,递归框架
    static Set<String> set=new HashSet<String>();//hashset去重

    public static void main(String[] args) {
        char[] a={'A','A','2','2','3','3','4','4'};
        //进入递归
        dfs(a,0);

        for (String x: set) {
            System.out.println(x);
        }

    }

    //怎么用全排列生成所有的情况了?
    public static void dfs(char[] a,int k){//字符数组,起始位置??
        if (k==a.length){//形成一个排列
            String s=new String(a);//用char数组生成一个字符串
            if (check(s)){//检查字符串是否满足要求
//                System.out.println(s);
                set.add(s);//set去重
            }
        }
        for(int i=k;i<a.length;i++){
            char t=a[k];//交换,确定这一位
            a[k]=a[i];
            a[i]=t;

            dfs(a,k+1);
            t=a[k];
            a[k]=a[i];//回溯。恢复到探测之前的状态
            a[i]=t;

        }

    }



    //检查字符之间的距离时候满足要求,
    /*
    string.lastIndexOf('char')-->返回倒数第一个char的位置!
    string.index('char')--->返回第一个char的位置
    0 1 2 3
    A 1 A d
    2-0=2
    注意差值在其题目标明的基础上+1
     */
    public 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

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗  < 1000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

多靠模拟

package q2014;

import java.util.Scanner;

/*
 * 标题:分糖果

    有n个小朋友围坐成一圈。老师给每个小朋友随机发偶数个糖果,然后进行下面的游戏:
    每个小朋友都把自己的糖果分一半给左手边的孩子。
    一轮分糖后,拥有奇数颗糖的孩子由老师补给1个糖果,从而变成偶数。
    反复进行这个游戏,直到所有小朋友的糖果数都相同为止。
    你的任务是预测在已知的初始糖果情形下,老师一共需要补发多少个糖果。

【格式要求】
    程序首先读入一个整数N(2<N<100),表示小朋友的人数。
    接着是一行用空格分开的N个偶数(每个偶数不大于1000,不小于2)
    要求程序输出一个整数,表示老师需要补发的糖果数。
 */
public class q8 {
	public static void main(String[] args) {
		Scanner scanner=new Scanner(System.in);
		int n=scanner.nextInt();
		int [] a=new int [n];
		for(int i=0;i<n;i++) {
			a[i]=scanner.nextInt();
		}
		int count=0;
//		System.out.println(n);
		while(true) {
			int t=a[0];//存着第一个数,后面最后一个数要用
			for(int i=0;i<=n-2;i++) {//到倒数第二个数就行,最后一个数单独处理
				a[i]-=a[i]/2;
				a[i]+=a[i+1]/2;
				
				//进行了一次变换,下面补全奇数
					if(a[i]%2!=0) {
						count++;
						a[i]++;
					}	
			}
			a[n-1]-=a[n-1]/2;
			a[n-1]+=t/2;
			if ((a[n - 1] & 1) == 1) {
				count++;
				a[n-1]++;
				
			}

			
			if (check(a)) {
				System.out.println(count);
				return ;
			}
			
		}
			//一直为真,只要没有满足那个条件
//		System.out.println(count);	
	}
	
	public  static boolean check(int[]a) {
		int t=a[0];
		for (int i = 0; i <=a.length-1; i++) {
			if (a[i]!=t) 
				return false;
		}
		return true;
	}
}

九、地宫取宝

标题:地宫取宝
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

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗  < 2000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
package q2014;

import java.util.Scanner;

public class q9 {
//	static long[][][][] cache = new long[51][51][14][14]; 
	static int m;
	static int n;
	static int k;
	static int[][]data;
	public static void main(String[] args) {
		// TODO Auto-generated method stub
/*
 * 输入一行3个整数,用空格分开:n m k (1<=n,m<=50, 1<=k<=12)
 * 接下来有 n 行数据,每行有 m 个整数 Ci (0<=Ci<=12)代表这个格子上的宝物的价值
 * 要求输出一个整数,表示正好取k个宝贝的行动方案数。该数字可能很大,输出它对 1000000007 取模的结果。

 * X 国王有一个地宫宝库。是 n x m 个格子的矩阵。每个格子放一件宝贝。
 * 每个宝贝贴着价值标签。
地宫的入口在左上角,出口在右下角。
小明被带到地宫的入口,国王要求他只能向右或向下行走。
走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。
当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明。
请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝。
 */
	//接受数据
		Scanner scanner=new Scanner(System.in);
		m=scanner.nextInt();
		n=scanner.nextInt();
		k=scanner.nextInt();
		data=new int[m][n];
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				data[i][j]=scanner.nextInt();
			}
		}
//		for(int[] a:data) {for(int b:a) {System.out.println(b);}}//检验		
		//剩下的就是使用dfs遍历所有的情况看看满足条件的有几个
		long ans=dfs(0, 0, -1, 0);
		System.out.println(ans);
		
	}
	//x,y:当前坐标  范围[0,m-1/n-1]  max:所遇最大值  cnt:已去宝贝数量
	public static long dfs(int x,int y,int max,int cnt) {
		if (x==n||y==m||cnt>k) {
			//越界
			return 0;			
		}
		int cur=data[x][y];//当格子的价值
		int ans =0;
		if (x==n-1&&y==m-1) {//最后一个
			if (cnt==k||(cnt==k-1&&cur>max)) {
				// cnt == k - 1, 再加上max这个值, cnt 刚好 == k
				return 1;				
			}
			return ans;
		}
		// 如果那个格子中的宝贝价值比小明手中任意宝贝价值都大, 小明就可以拿起它
		if (cur>max) {
			ans+=dfs(x, y+1, cur, cnt+1);
			ans+=dfs(x+1, y, cur, cnt+1);	
		}
		//当然也可以不拿
		ans+=dfs(x, y+1, max, cnt);
		ans+=dfs(x+1, y, max, cnt);
		
		return ans%1000000007;
		
	}

}

本题关键还是要懂得深度搜索,加结合具体题目,才能完成

十、矩阵翻硬币

标题:矩阵翻硬币

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

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

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

    其中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;
对于100%的数据,n、m <= 10^1000(10的1000次方)。

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗  < 2000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

总结

01 武功秘籍 书的构造方式,思维题
02 切面条 发现规律,思维题
03 猜字母 数组中元素的挪动和挤压
04 大衍数列 考察奇偶数判断
05 圆周率 细心,极限思维
06 奇怪的分式 枚举abcd,分数运算,最大公约数
07 扑克排序 带重复元素的全排列
08 分糖果 模拟
**09 地宫取宝 搜索->记忆型递归,因为子问题重复求解
****10 矩阵翻硬币 数学;字符,字符串,BigInteger的互相转化=

2015年真题

一、三角形的面积

三角形面积

如【图1】所示。图中的所有小方格面积都是1。

img

那么,图中的三角形面积应该是多少呢?

请填写三角形的面积。不要填写任何多余内容或说明性文字。

28

普通计算

二、立方变自身

立方变自身

观察下面的现象,某个数字的立方,按位累加仍然等于自身。
1^3 = 1
8^3 = 512 5+1+2=8
17^3 = 4913 4+9+1+3=17

请你计算包括1,8,17在内,符合这个性质的正整数一共有多少个?

请填写该数字,不要填写任何多余的内容或说明性的文字。

方法1:相当于水仙花数,求每个位置上的数

package q2015;

public class q2 {

	/**
	 * @param args
	 */
	/**
	 * @param args
	 */
	/**
	 * @param args
	 */
	public static void main(String[] args) {
//		long n=Integer.MAX_VALUE;//范围到100,即可
		int a=0;
		int b;int c;
		int d;int e;
		int f;int count=0;
		
		for (int i=1;i<=100;i++) {
			 int a3=i*i*i;
			 a=a3/1%10;
			 b=a3/10%10;
			 c=a3/100%10;
			 d=a3/1000%10;
			 e=a3/10000%10;
			 f=a3/100000%10;
			 if (a+b+c+d+e+f==i) {
				count++;
			}
			}
		System.out.println(count);
	}
}

第二种方法:

将数字转化为字符串,再利用charAt()计算其于‘0’的差值

		int ans=0;
		for (int i = 1; i < 99; i++) {
			int aaa=i*i*i;
			int sum=sum(aaa);
			if (sum==i) {
				System.out.println(i);
				ans++;
			}
			
		}
		System.out.println(ans);
	}
	
	
	public static int sum(int x) {
		//int -->str
		String aString=String.valueOf(x);
		int sum=0;
		for (int i = 0; i < aString.length(); i++) {
			sum=sum+aString.charAt(i)-'0';
			
		}
		return sum;
		
	}

三、三羊献瑞

三羊献瑞

观察下面的加法算式:

祥 瑞 生 辉
+ 三 羊 献 瑞
-------------------
三 羊 生 瑞 气

(如果有对齐问题,可以参看【图1.jpg】)

img

其中,相同的汉字代表相同的数字,不同的汉字代表不同的数字。

请你填写“三羊献瑞”所代表的4位数字(答案唯一),不要填写任何多余内容

1。根据公式可知,“三”+“祥”进了一位“三”,所以“三”=1

剩下的遍历吧><

package q2015;

public class q3 {
	
public static void main(String[] args) {
	for (int a = 0; a <=9; a++) {
		for (int b = 0; b<=9; b++) {
			if (a!=b) {
				for (int c= 0; c<=9; c++) {
					if (c!=a&&c!=b) {
						for (int d = 0; d <=9; d++) {
							if (d!=c&&d!=b&&d!=a) {
								for(int f=0;f<=9;f++) {
									if (f!=a&f!=b&&f!=c&f!=d) {
										for(int g=0;g<=9;g++) {
											if (g!=a&g!=b&g!=c&g!=d&g!=1&g!=f) {
												for(int x=0;x<=9;x++) {
													if (x!=a&x!=b&x!=c&x!=d&x!=f&x!=g&x!=1) {
												
														if (a*1000+b*100+c*10+d+1*1000+f*10+g*10+b==1*10000+f*1000+c*100+b*10+x) {
															System.out.println(a+" "+b+" "+c+" "+d+" "+f+" "+g+" "+x);
														}
													}

												}
											}
										}
									}
								}
							}
							
						}
					}
					
				}
			}
		}
	}
	
}
}

四、循环节长度

循环节长度

两个整数做除法,有时会产生循环小数,其循环部分称为:循环节。
比如,11/13=6=>0.846153846153.....  其循环节为[846153] 共有6位。
下面的方法,可以求出循环节的长度。

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

    public static int f(int n, int m)
    {undefined
        n = n % m;    
        Vector v = new Vector();
        
        for(;;)
        {undefined
            v.add(n);
            n *= 10;
            n = n % m;
            if(n==0) return 0;
            if(v.indexOf(n)>=0)  __________return ____v.size()-v.indexof(n)_____ ;  //填空
        }
    }

方法:

模拟,多试几个数,找到规律即可

v.size()-v.indexof(n)

五、九数组分数

九数组分数

1,2,3...9 这九个数字组成一个分数,其值恰好为1/3,如何组法?

下面的程序实现了该功能,请填写划线部分缺失的代码。

public class A
{
    public static void test(int[] x)
    {undefined
        int a = x[0]*1000 + x[1]*100 + x[2]*10 + x[3];
        int b = x[4]*10000 + x[5]*1000 + x[6]*100 + x[7]*10 + x[8];        
        if(a*3==b) System.out.println(a + " " + b);
    }
    
    public static void f(int[] x, int k)
    {undefined
        if(k>=x.length){undefined
            test(x);
            return;
        }
        
        for(int i=k; i<x.length; i++){
            {int t=x[k]; x[k]=x[i]; x[i]=t;}
            f(x,k+1);
            ___t=x[k]; x[k]=x[i]; x[i]=t;___       // 填空
        }
    }
    
    public static void main(String[] args)
    {undefined
        int[] x = {1,2,3,4,5,6,7,8,9};        
        f(x,0);
    }
}

注意,只能填写缺少的部分,不要重复抄写已有代码。不要填写任何多余的文字。

全排列模板!!!

先纵后横 —> img

六、加法变乘法

加法变乘法

我们都知道:1+2+3+ ... + 49 = 1225
现在要求你把其中两个不相邻的加号变成乘号,使得结果为2015

比如:
1+2+3+...+10*11+12+...+27*28+29+...+49 = 2015
就是符合要求的答案。

请你寻找另外一个可能的答案,并把位置靠前的那个乘号左边的数字提交(对于示例,就是提交10)。

注意:需要你提交的是一个整数,不要填写任何多余的内容。

//简单枚举:

一般情况下,我们可能遍历整个+号尝试暴力循环

但是这个题目不需要,将+号变为*号,我们可以只关注修改的部分

2015—1225=修改值-原来值

接下来就是查找两个*号的情况了,使用暴力解法即可

七、牌型种数

牌型种数

小明被劫持到X赌城,被迫与其他3人玩牌。
一副扑克牌(去掉大小王牌,共52张),均匀发给4个人,每个人13张。
这时,小明脑子里突然冒出一个问题:
如果不考虑花色,只考虑点数,也不考虑自己得到的牌的先后顺序,自己手里能拿到的初始牌型组合一共有多少种呢?

请填写该整数,不要填写任何多余的内容或说明文字。

解法一:暴力

**一共有13种牌型(A,2,3,4,5,6,7,8,9,10,J,Q,K),每种可以拿到0~4张,只要牌数达到13张就满足条件。这道题可以用**暴力破解**或者*回溯穷举再剪枝*的方法做。

package q2015;

public class q71 {


    public static int count = 0;

    public static void main(String[] args) {
        for (int a = 0; a <= 4; a++) {
            for (int b = 0; b <= 4; b++) {
                for (int c = 0; c <= 4; c++) {
                    for (int d = 0; d <= 4; d++) {
                        for (int e = 0; e <= 4; e++) {
                            for (int f = 0; f <= 4; f++) {
                                for (int g = 0; g <= 4; g++) {
                                    for (int h = 0; h <= 4; h++) {
                                        for (int i = 0; i <= 4; i++) {
                                            for (int j = 0; j <= 4; j++) {
                                                for (int k = 0; k <= 4; k++) {
                                                    for (int l = 0; l <= 4; l++) {
                                                        for (int m = 0; m <= 4; m++) {
                if ((a + b + c + d + e + f + g + h + i + j + k + l   + m) == 13) {
                                                                count++;
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        System.out.println(count);
    }
}

方法二:回溯剪枝

ps:回溯法是每次研究当前类型的牌可以拿几张,注意还原sum的值就可以了。

package q2015;

public class q72 {
    public static int sum = 0;
    public static int count = 0;

    public static void calculate(int kind) {
        if (sum > 13 || kind > 13)
            return;
        if (kind == 13 && sum == 13) {
            count++;
            return;
        }

        if (kind < 13) {
            for (int i = 0; i < 5; i++) {
                sum += i;
                calculate(kind + 1);
                sum -= i; // 还原标记
            }
        }

    }

    public static void main(String[] args) {
        calculate(0);
        System.out.println(count);
    }

}

r另一种回溯?

package q2015;

public class q7 {
	private static int ans;
	 
	public static void main(String[] args) {
		f(0, 0);
		System.out.println(ans);
	}
 
	// 13堆牌,每堆4个, 每堆可选0到4个, 只要牌的总数为13即可
	// k: 哪种牌; cnt: 总共分配了几张牌
	private static void f(int k, int cnt) {
		if (k > 13 || cnt > 13)
			return;
		if (k == 13 && cnt == 13) {
			ans++;
			return;
		}
		// cnt 每一种牌出现的次数,cnt逐步上升
		// cnt==13,牌型种数+1,返回
		for (int i = 0; i < 5; i++) {
			f(k + 1, cnt + i);
		}
	}

}

八、饮料换购

饮料换购

乐羊羊饮料厂正在举办一次促销优惠活动。乐羊羊C型饮料,凭3个瓶盖可以再换一瓶C型饮料,并且可以一直循环下去,但不允许赊账。

请你计算一下,如果小明不浪费瓶盖,尽量地参加活动,那么,对于他初始买入的n瓶饮料,最后他一共能得到多少瓶饮料。

输入:一个整数n,表示开始购买的饮料数量(0<n<10000)
输出:一个整数,表示实际得到的饮料数

例如:
用户输入:
100
程序应该输出:
149

用户输入:
101
程序应该输出:
151


资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗  < 1000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

没看懂解题方法

package q2015;

import java.util.Scanner;

public class q81 {
public static void main(String[] args) {
	Scanner Scanner=new Scanner(System.in);
	int n=Scanner.nextInt();
	int ans=0;//最后的答案
	while(n>=3) {
		n=n-2;
		ans=ans+3;
	}
	ans=ans+n;
	System.out.println(ans);
	
}
}

九、垒骰子

垒骰子

赌圣atm晚年迷恋上了垒骰子,就是把骰子一个垒在另一个上边,不能歪歪扭扭,要垒成方柱体。
经过长期观察,atm 发现了稳定骰子的奥秘:有些数字的面贴着会互相排斥!
我们先来规范一下骰子:1 的对面是 4,2 的对面是 5,3 的对面是 6。
假设有 m 组互斥现象,每组中的那两个数字的面紧贴在一起,骰子就不能稳定的垒起来。 atm想计算一下有多少种不同的可能的垒骰子方式。
两种垒骰子方式相同,当且仅当这两种方式中对应高度的骰子的对应数字的朝向都相同。
由于方案数可能过多,请输出模 10^9 + 7 的结果。

不要小看了 atm 的骰子数量哦~

「输入格式」
第一行两个整数 n m
n表示骰子数目
接下来 m 行,每行两个整数 a b ,表示 a 和 b 不能紧贴在一起。

「输出格式」
一行一个数,表示答案模 10^9 + 7 的结果。

「样例输入」
2 1
1 2

「样例输出」
544

「数据范围」
对于 30% 的数据:n <= 5
对于 60% 的数据:n <= 100
对于 100% 的数据:0 < n <= 10^9, m <= 36


资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗  < 2000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

十、生命之树

生命之树

在X森林里,上帝创建了生命之树。

他给每棵树的每个节点(叶子也称为一个节点)上,都标了一个整数,代表这个点的和谐值。
上帝要在这棵树内选出一个非空节点集S,使得对于S中的任意两个点a,b,都存在一个点列 {a, v1, v2, ..., vk, b} 使得这个点列中的每个点都是S里面的元素,且序列中相邻两个点间有一条边相连。

在这个前提下,上帝要使得S中的点所对应的整数的和尽量大。
这个最大的和就是上帝给生命之树的评分。

经过atm的努力,他已经知道了上帝给每棵树上每个节点上的整数。但是由于 atm 不擅长计算,他不知道怎样有效的求评分。他需要你为他写一个程序来计算一棵树的分数。

「输入格式」
第一行一个整数 n 表示这棵树有 n 个节点。
第二行 n 个整数,依次表示每个节点的评分。
接下来 n-1 行,每行 2 个整数 u, v,表示存在一条 u 到 v 的边。由于这是一棵树,所以是不存在环的。

「输出格式」
输出一行一个数,表示上帝给这棵树的分数。

「样例输入」
5
1 -2 -3 4 5
4 2
3 1
1 2
2 5

「样例输出」
8

「数据范围」
对于 30% 的数据,n <= 10
对于 100% 的数据,0 < n <= 10^5, 每个节点的评分的绝对值不超过 10^6 。

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗  < 3000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
————————————————

小结

01 三角形面积 热身 不用编程
02 立方变自身 简单枚举
03 三羊献瑞 简单枚举 小技巧
*04 循环节长度 有坑 逻辑
05 九数组分数 全排列 带分数
06 加法变乘法 简单枚举 小技巧
07 牌型种数 递归
08 饮料换购 模拟
09 垒骰子 递归-动规-矩阵快速幂
10 生命之树 Java中递归最多1万层

2016年真题

一、煤球数目

煤球数目

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

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

请填表示煤球总数目的数字。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

package q2016;

public class q1 {
	public static void main(String[] args) {

		int a[]=new int[101];
		a[1]=1;
		for (int i=2;i<=100;i++) {//!!!注意边界
			a[i]=a[i-1]+i;
			
		}
		int sum=0;
		System.out.println(a[6]);
		for(int x:a) {
			sum=sum+x;
			System.out.println(x);
		}
		System.out.println(sum);
	}
}

二、生日蜡烛

生日蜡烛

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

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

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

请填写他开始过生日party的年龄数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。


package q2016;

public class q2 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		int sum=0;
	    int[]a= {26,27,28,29,30,31,32,33};
	    for(int x:a) {
	    	sum+=x;
	    }
	    System.out.println(sum);
	    
	    System.out.println((26+33)*(33-26+1)/2);
	    
	    /*
	     * 枚举两个数,计算这两个数之间的和是否=236
	     */
	    
	    for(int i=1;i<100;i++) {
	    	for(int j=i;j<100;j++) {
	    		if ((i+j)*(j-i+1)/2==236) {
	    			System.out.println("i"+i+j);
					
				}
	    	}
	    }
	}

}

三、凑算式

img

凑算式

     B      DEF
A + --- + ------- = 10
     C      GHI
     
(如果显示有问题,可以参见【图1.jpg】)


图1.jpg

这个算式中A~I代表1~9的数字,不同的字母代表不同的数字。

比如:
6+8/3+952/714 就是一种解法,
5+3/1+972/486 是另一种解法。

这个算式一共有多少种解法?

注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。

!!!carefull:

注意:java里面除号“/”是整除的意思,所以在这题中我们要先通分,再算除法,否则就会漏掉很多情况。

(

if (a[0]+a[1]/a[2]+(a[3]*100+a[4]*10+a[5])/(a[6]*100+a[7]*10+a[8])==10 && 
    (a[1] * (a[6]*100+a[7]*10+a[8]) + a[2] * (a[3]*100+a[4]*10+a[5])) % (a[2] *  (a[6]*100+a[7]*10+a[8]))==0) 

    //vs
   
if ((a[1] * y + a[2] * x) % (a[2] * y) == 0 && a[0] + (a[1] * y + a[2] * x) / (a[2] * y) == 10) 

package q2016;

public class q3 {
	static int count=0;
public static void main(String[] args) {
	int[] a= {1,2,3,4,5,6,7,8,9};
	dfs(a, 0);
	System.out.println(count);
}

public static void dfs(int[] a,int k) {

	int x = a[3] * 100 + a[4] * 10 + a[5]; // DEF
	int y = a[6] * 100 + a[7] * 10 + a[8]; // GHI

	if (k==a.length) {
		if ((a[1] * y + a[2] * x) % (a[2] * y) == 0 && a[0] + (a[1] * y + a[2] * x) / (a[2] * y) == 10) {
		count++;}
	}
	for(int i=k;i<a.length;i++) {
		int t=a[i];
		a[i]=a[k];
		a[k]=t;
		dfs(a, k+1);
		t=a[i];
		a[i]=a[k];
		a[k]=t;	
	}
}
}

四、分小组

分小组

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
{undefined
    public static String remain(int[] a)
    {undefined
        String s = "";
        for(int i=0; i<a.length; i++){undefined
            if(a[i] == 0) s += (char)(i+'A');
        }    
        return s;
    }
    
    public static void f(String s, int[] a)
    {undefined
        for(int i=0; i<a.length; i++){undefined
            if(a[i]==1) continue;
            a[i] = 1;
            for(int j=i+1; j<a.length; j++){undefined
                if(a[j]==1) continue;
                a[j]=1;
                for(int k=j+1; k<a.length; k++){undefined
                    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)
    {undefined
        int[] a = new int[9];        
        a[0] = 1;
        
        for(int b=1; b<a.length; b++){undefined
            a[b] = 1;
            for(int c=b+1; c<a.length; c++){undefined
                a[c] = 1;
                String s = "A" + (char)(b+'A') + (char)(c+'A');
                f(s,a);
                a[c] = 0;
            }
            a[b] = 0;
        }
    }
}

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

注意:不要填写任何已有内容或说明性文字。
System.out.println(s + (char) (i + 'A') + (char) (j + 'A') + (char) (k + 'A') + remain(a));

五、抽签

抽签

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


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

注意:不要填写任何已有内容或说明性文字。

注:全排列的参数关系要再看看

package q2016;

public class q5 {
	public static void f(int[] a, int k, int n, String s)
	//a表示每个国家可以派出的最多人数
	/**
	 * k:(选择那个国家)k=a数组的下表
	 * n:排出的人数=5
	 * s:缓冲字符串
	 */
    {
        if(k==a.length){ 
            if(n==0) System.out.println(s);
            return;
        }
        
        String s2 = s;
        for(int i=0; i<=a[k]; i++){//将k国家排除i人
            
//            _____________________________;   //填空位置
            /*要搞清楚参数的翻译,以及参数的变换方向
            */
        	f(a, k + 1, n - i, s2);//递归中k变大,n必然减小
            s2 += (char)(k+'A');//国别的符号
        }
    }
    
    public static void main(String[] args)
    {
        int[] a = {4,2,2,1,1,3};
        
        f(a,0,5,"");
    }
}

六、方格填数

方格填数

如下的10个格子
±-±-±-+
| | | |
±-±-±-±-+
| | | | |
±-±-±-±-+
| | | |
±-±-±-+

(如果显示有问题,也可以参看【图1.jpg】)

img

填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)

一共有多少种可能的填数方案?

请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

方格填数:

递归回溯:八皇后(最经典)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6nfoh7rn-1651583579174)(https://gitee.com/cl2854697833/my-picture/raw/master/img/202204022221282.png)]

package q2016;
import static java.lang.Math.*;

public class q6 {
	//将数组固定到格子中,这样只要枚举出所有可能即可
	static int[] a= {0,1,2,3,4,5,6,7,8,9};
	static int count=0;
	
	//定义一个检测
	public  static boolean check () {
		if (abs(a[0] - a[1]) == 1 || abs(a[0] - a[3]) == 1 || abs(a[0] - a[4]) == 1 || abs(a[0] - a[5]) == 1 ||
				abs(a[1] - a[2]) == 1 || abs(a[1] - a[4]) == 1 || abs(a[1] - a[5]) == 1 || abs(a[1] - a[6]) == 1 ||
				abs(a[2] - a[5]) == 1 || abs(a[2] - a[6]) == 1 ||
				abs(a[3] - a[4]) == 1 || abs(a[3] - a[7]) == 1 || abs(a[3] - a[8]) == 1 ||
				abs(a[4] - a[5]) == 1 || abs(a[4] - a[7]) == 1 || abs(a[4] - a[8]) == 1 || abs(a[4] - a[9]) == 1 ||
				abs(a[5] - a[6]) == 1 || abs(a[5] - a[8]) == 1 || abs(a[5] - a[9]) == 1 ||
				abs(a[6] - a[9]) == 1 ||
				abs(a[7] - a[8]) == 1 ||
				abs(a[8] - a[9]) == 1) {
			return false;
		}
		return true;
	}
	public static void dfs(int k) {
		if (k==a.length) {//找出来一种可能
			if (check()) {
				count++;
			}
		}
		
		for(int i=k;i<a.length;i++) {
			int t=a[i];
			a[i]=a[k];
			a[k]=t;
			dfs(k+1);
			 t=a[i];
			a[i]=a[k];
			a[k]=t;
		}
		
	}
	
	
	public static void main(String[] args) {
		dfs(0);
		System.out.println(count);
}
}

七、剪邮票

剪邮票

如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取 。

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

请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

img img img

全排列+连通性检测+set去重

image-20220402160520407
package q2016;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class q7 {
static int[] a= {0,0,0,0,0,0,0,1,1,1,1,1};
static int ans=0;
public static void dfs(int[][]g ,int i,int j) {//检测连通性
	g[i][j]=0;//使用了,标记为0
	if (i-1>=0&&g[i-1][j]==1) { dfs(g, i-1, j);	}//检测上一行的数字是不是满足要求
	if(i+1<=2&&g[i+1][j]==1) {dfs(g, i+1, j);}//下
	//左
	if (j-1>=0&&g[i][j-1]==1) {dfs(g, i, j-1);}
	//右
	if (j+1<=3&&g[i][j+1]==1) {dfs(g, i, j+1);}
	
}
public static boolean check(){//检测某一种排列是否满足要求
	int [][] g=new int[3][4];//使用这个二维数组进行连通性检测,将一维数组映射到二维数组上
	for (int i = 0; i < 3; i++) {//遍历每一个元素,初始化
		for (int j = 0; j < 4; j++) {
			if(a[i*4+j]==1) {
				g[i][j]=1;
			}else {
				g[i][j]=0;
			}
		}		
	}
	//2。计算连通块的个数
	int cnt=0;
	for (int i = 0; i < 3; i++) {//对于每一个元素,开始计算连通性,我们只要有一个联通块
		for (int j = 0; j < 4; j++) {
			if (g[i][j]==1) {
				dfs(g, i, j);//像洪水般席卷其四周的数字,如果
				cnt++;
			}
		}
	}
	return cnt==1;
}


public static void f(int k) {	
	if(k==a.length) {
		if (!isExist()&&check()) {
			ans++;
		}
	}
		
	for (int i=k;i<12;i++) {
		int t=a[i];
		a[i]=a[k];
		a[k]=t;
		f(k+1);
		t=a[i];
		a[i]=a[k];
		a[k]=t;
	}
	
}

static Set<String>	set=new HashSet<String>();
	private static boolean isExist() {
//		a2s将数组转换为字符串
		String aaString=Arrays.toString(a);
		if (!set.contains(aaString)) {
			set.add(aaString);
			return false;
		}else {
			return true;
		}
		
}


	public static void main(String[] args) {
		// TODO Auto-generated method stub
f(0);
System.out.println(ans);
	}

}

八、四平方和

四平方和

四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多4个正整数的平方和。
如果把0包括进去,就正好可以表示为4个数的平方和。

比如:
5 = 0^2 + 0^2 + 1^2 + 2^2
7 = 1^2 + 1^2 + 1^2 + 2^2
(^符号表示乘方的意思)

对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对4个数排序:
0 <= a <= b <= c <= d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法

程序输入为一个正整数N (N<5000000)
要求输出4个非负整数,按从小到大排序,中间用空格分开

例如,输入:
5
则程序应该输出:
0 0 1 2

再例如,输入:
12
则程序应该输出:
0 2 2 2

再例如,输入:
773535
则程序应该输出:
1 1 267 838

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 3000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

image-20220402193600926

img

image-20220402193634839

package q2016;

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.math.*;
public class q8 {
//public static void main(String[] args) {
//	Scanner scanner=new Scanner(System.in);
//	int n=scanner.nextInt();
//	for(int a=0;a<n;a++) {
//		for (int b=a;b<n;b++) {
//			for (int c=b;c<n;c++) {
//				for(int d=c;d<n;d++) {
//					if(a*a+b*b+c*c+d*d==n) {
//						System.out.println(a+" "+b+" "+c+" "+d);
//					}
//				}
//			}
//		}
//	}
//}
static int N;
static Map<Integer, Integer> cache=new HashMap<Integer, Integer>();

public static void main(String[] args) {
	//1、减少n的范围
	//	2、减少变量 使用a、b表示c,d?
	Scanner scanner=new Scanner(System.in);
	 N=scanner.nextInt();
	
	for(int c=0;c*c<=N/2;c++) {
		for (int d=c;d*d+c*c<=N;d++) {
			if (cache.get(c*c+d*d)==null) {
				cache.put(c*c+d*d,c);
			}
		}
	}
	
	for(int a=0;a*a<=N/4;a++) {
		for (int b=a;b*b+a*a<=N/2;b++) {
			if(cache.get(N-a*a-b*b)!=null) {
				int c=cache.get(N-a*a-b*b);
				int d=(int)Math.sqrt(N-a*a-b*b-c*c);
				System.out.printf("%d %d %d %d\n",a,b,c,d);
				return;//加上return,就只返回一个
			}
		}
	}	
}
}

九、取球博弈

取球博弈

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

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

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

输出格式:
一行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

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 3000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

现实的子问题显然可以用递归

尝试————>DFS

image-20220402193848596

image-20220402195034294

博弈问题的转换都是这样><

import java.util.Arrays;
import java.util.Map;
import java.util.Scanner;
 
/*
取球博弈
两个人玩取球的游戏。
一共有N个球,每人轮流取球,每次可取集合{n1,n2,n3}中的任何一个数目。
如果无法继续取球,则游戏结束。
此时,持有奇数个球的一方获胜。
如果两人都是奇数,则为平局。
假设双方都采用最聪明的取法,
第一个取球的人一定能赢吗?
试编程解决这个问题。
输入格式:
第一行3个正整数n1 n2 n3,空格分开,表示每次可取的数目 (0<n1,n2,n3<100)
第二行5个正整数x1 x2 ... x5,空格分开,表示5局的初始球数(0<xi<1000)
输出格式:
一行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
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗  < 3000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
*/
 
/*
1 7 8
900 901 903 905 907
0 + - - + */
public class _08取球博弈 {
 
  private static int[] n;
 
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    n = new int[3];
    for (int i = 0; i < 3; i++) {
      n[i] = sc.nextInt();
    }
    Arrays.sort(n);//排序
    for (int i = 0; i < 5; i++) {
      int num = sc.nextInt();
      char res = f(num, 0, 0);
      System.out.print(res + " ");
    }
    System.out.println();
  }
static char[][][]cache = new char[1000][2][2];
  /**
   * 参数代表着当前取球人面临的局面
   * @param num 球的总数
   * @param me 我方持有的数目-->我方数目的奇偶性
   * @param you 对手持有的数目-对方数目的奇偶性
   * @return
   */
  private static char f(int num, int me, int you) {
    if (num<n[0])//不够取
    {
      if ((me&1)==1&&(you&1)==0)return '+';
      else if ((me&1)==0&&(you&1)==1)return '-';
      else return '0';
    }
    if (cache[num][me][you]!='\0')return cache[num][me][you];
    boolean ping = false;
    for (int i = 0; i < 3; i++) {
      if (num >= n[i]) {
        char res = f(num - n[i], you, (n[i]&1)==0?me:(1-me));//注意此处,传递me和you的奇偶性
        if (res == '-')
        {
          cache[num][me][you]='+';
          return '+';
        }
        if (res == '0')
          ping = true;
      }
    }
    //如果能走到第这行,说明不存在对手输的情况,那么是否存在平的情况
    if (ping)
    {
      cache[num][me][you]='0';
      return '0';
    }
    else
    {
      cache[num][me][you]='-';
      return '-';
    }
  }
}

十、压缩变换

压缩变换

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

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

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

比如,序列(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

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 3000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理

30分解法:

image-20220402210540335

package provincialGames_07_2016_JavaB;
 
import java.util.*;
 
public class A10_压缩变换 { // 30分
	static Map<Integer, Integer> lastIndex = new HashMap<Integer, Integer>();// 数字与下标的映射
	static int[] data;// 记录原始数据
	static int[] ans;// 记录答案
	private static int n;
 
	public static void main(String[] args) {
		// 处理输入
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		data = new int[n];
		ans = new int[n];
		for (int i = 0; i < n; i++) {
			int num = sc.nextInt();
			data[i] = num;
			if (lastIndex.get(num) == null) {// 没出现过
				ans[i] = -num;
			} else {
				// 统计p_num和i之间有多少不同的数字
				Set<Integer> set = new HashSet<Integer>();
				for (int j = lastIndex.get(num) + 1; j < i; j++) {
					set.add(data[j]);
				}
				ans[i] = set.size();
			}
			lastIndex.put(num, i);// 更新数字最后出现的位置
		}
		for (int i = 0; i < n; i++) {
			System.out.print(ans[i] + " ");
		}
	}
}

小结

01 煤球数目 找规律 简单计算
02 生日蜡烛 枚举: 1两个年龄 2过生日的次数,等差数列求和的公式
03 凑算式 全排列+check
04 分小组 逻辑
05 抽签递归,搞清楚参数的含义和参数的变化方向
06 方格填数 全排列+check
07**** 剪邮票 全排列(带重复元素的全排列,要用套路全排套路1) +标注(二维数组上标注01) +dfs求连通块数目
08 四平方和 枚举优化(hash缓存)
09*** 取球博弈 典型的博弈框架(带平局)
10**** 压缩变换 hash查找+标注(一维数组上标注01便于区间求和) +区间树(线段树)

private static char f(int num, int me, int you) {
if (num<n[0])//不够取
{
if ((me&1)==1&&(you&1)==0)return ‘+’;
else if ((me&1)==0&&(you&1)==1)return ‘-’;
else return ‘0’;
}
if (cache[num][me][you]!=‘\0’)return cache[num][me][you];
boolean ping = false;
for (int i = 0; i < 3; i++) {
if (num >= n[i]) {
char res = f(num - n[i], you, (n[i]&1)==0?me:(1-me));//注意此处,传递me和you的奇偶性
if (res == ‘-’)
{
cache[num][me][you]=‘+’;
return ‘+’;
}
if (res == ‘0’)
ping = true;
}
}
//如果能走到第这行,说明不存在对手输的情况,那么是否存在平的情况
if (ping)
{
cache[num][me][you]=‘0’;
return ‘0’;
}
else
{
cache[num][me][you]=‘-’;
return ‘-’;
}
}
}






### 十、压缩变换

>
>
>压缩变换
>
>小明最近在研究压缩算法。
>他知道,压缩的时候如果能够使得数值很小,就能通过熵编码得到较高的压缩比。
>然而,要使数值很小是一个挑战。
>
>最近,小明需要压缩一些正整数的序列,这些序列的特点是,后面出现的数字很大可能是刚出现过不久的数字。对于这种特殊的序列,小明准备对序列做一个变换来减小数字的值。
>
>变换的过程如下:
>从左到右枚举序列,每枚举到一个数字,如果这个数字没有出现过,刚将数字变换成它的相反数,如果数字出现过,则看它在原序列中最后的一次出现后面(且在当前数前面)出现了几种数字,用这个种类数替换原来的数字。
>
>比如,序列(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
>
>
>资源约定:
>峰值内存消耗(含虚拟机) < 256M
>CPU消耗  < 3000ms
>
>
>请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
>
>所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
>注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
>注意:主类的名字必须是:Main,否则按无效代码处理 	



30分解法:

[外链图片转存中...(img-ocYNes4c-1651583579176)]





```java
package provincialGames_07_2016_JavaB;
 
import java.util.*;
 
public class A10_压缩变换 { // 30分
	static Map<Integer, Integer> lastIndex = new HashMap<Integer, Integer>();// 数字与下标的映射
	static int[] data;// 记录原始数据
	static int[] ans;// 记录答案
	private static int n;
 
	public static void main(String[] args) {
		// 处理输入
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		data = new int[n];
		ans = new int[n];
		for (int i = 0; i < n; i++) {
			int num = sc.nextInt();
			data[i] = num;
			if (lastIndex.get(num) == null) {// 没出现过
				ans[i] = -num;
			} else {
				// 统计p_num和i之间有多少不同的数字
				Set<Integer> set = new HashSet<Integer>();
				for (int j = lastIndex.get(num) + 1; j < i; j++) {
					set.add(data[j]);
				}
				ans[i] = set.size();
			}
			lastIndex.put(num, i);// 更新数字最后出现的位置
		}
		for (int i = 0; i < n; i++) {
			System.out.print(ans[i] + " ");
		}
	}
}

小结

01 煤球数目 找规律 简单计算
02 生日蜡烛 枚举: 1两个年龄 2过生日的次数,等差数列求和的公式
03 凑算式 全排列+check
04 分小组 逻辑
05 抽签递归,搞清楚参数的含义和参数的变化方向
06 方格填数 全排列+check
07**** 剪邮票 全排列(带重复元素的全排列,要用套路全排套路1) +标注(二维数组上标注01) +dfs求连通块数目
08 四平方和 枚举优化(hash缓存)
09*** 取球博弈 典型的博弈框架(带平局)
10**** 压缩变换 hash查找+标注(一维数组上标注01便于区间求和) +区间树(线段树)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是蓝桥杯中级组历年C++: 2019年蓝桥杯省赛 - 第一:求和 - 第二:小球下落 - 第三:字符串反转 - 第四:图像旋转 - 第五:矩阵计算 - 第六:数字分解 - 第七:排列与组合 - 第八:数组去重 2018年蓝桥杯省赛 - 第一:年龄与疾病 - 第二:津津的储蓄计划 - 第三:统计字符 - 第四:拼图游戏 - 第五:简化路径 - 第六:皇后问 - 第七:独立的小球 - 第八:生命游戏 2017年蓝桥杯省赛 - 第一:简单计算器 - 第二:数字排序 - 第三:大整数加法 - 第四:数字三角形 - 第五:随机数生成器 - 第六:词典 - 第七:数码管 - 第八:磁盘分区 2016年蓝桥杯省赛 - 第一:猜字母 - 第二:字符串的插入和删除 - 第三:矩阵乘法 - 第四:大数加法 - 第五:图像旋转 - 第六:数列求和 - 第七:矩阵变换 - 第八:货车运输问 2015年蓝桥杯省赛 - 第一:奇偶排序 - 第二:火车进站 - 第三:二叉树遍历 - 第四:矩阵乘法 - 第五:立方体表面积 - 第六:计算器 - 第七:数独 - 第八:晶体生长 2014年蓝桥杯省赛 - 第一:逆序对 - 第二:小球下落 - 第三:最长公共子序列 - 第四:矩阵乘法 - 第五:矩阵计算 - 第六:整数划分 - 第七:排列 - 第八:猜数字 2013年蓝桥杯省赛 - 第一:计算器 - 第二:数组逆序重放 - 第三:图像旋转 - 第四:表达式求值 - 第五:矩阵计算 - 第六:拨钟问 - 第七:递推数列 - 第八:小明放学 2012年蓝桥杯省赛 - 第一:小明放学 - 第二:求最大子段和 - 第三:数独 - 第四:矩阵计算 - 第五:图像旋转 - 第六:八皇后问 - 第七:矩阵变换 - 第八:单词接龙 2011年蓝桥杯省赛 - 第一:求最大子段和 - 第二:逆序对 - 第三:数独 - 第四:矩阵计算 - 第五:矩阵变换 - 第六:八皇后问 - 第七:括号匹配 - 第八:火车进站 以上是蓝桥杯中级组历年C++,希望能对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奥丁之眼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值