第十三届蓝桥杯校内模拟赛第二期记录

第1题

小蓝的IP地址为 192.168.*.21,其中 * 是一个数字,请问这个数字最大可能是多少?

思路:常识

答案:255

第2题

如果一个整数 g 能同时整除整数 A 和 B,则称 g 是 A 和 B 的公约数。例如:43 是 86 和 2021 的公约数。
请问在 1(含) 到 2021(含) 中,有多少个数与 2021 存在大于 1 的公约数。请注意 2021 和 2021 有大于 1 的公约数,因此在计算的时候要算一个。

思路:遍历2~2021,判断每个数与2021是否有非1的公约数,有就增加一个结果。

答案:89

代码:

public class Main {

    // 求最大公约数,保证a>=b
    private static int gcd(int a, int b) {
        return a % b == 0 ? b : gcd(b, a % b);
    }

    // num与2021是否有非1的公约数
    private static boolean fun(int num) {
        if(num <= 1) return false;
        if(num > 2021) return false;

        if(gcd(2021, num) != 1) return true;
        else return false;
    }

    public static void main(String[] args) {
        int res = 0;
        for(int i = 2; i <= 2021; i++) {
            if(fun(i)) res++;
        }
        System.out.println(res);
    }
}

第3题

2021 是一个非常特殊的数,它可以表示成两个非负整数的平方差,2021 = 45 * 45 - 2 * 2。
2025 也是同样特殊的数,它可以表示成 2025 = 45 * 45 - 0 * 0。
请问,在 1 到 2021 中有多少个这样的数?
请注意,有的数有多种表示方法,例如 9 = 3 * 3 - 0 * 0 = 5 * 5 - 4 * 4,在算答案时只算一次。

思路:遍历范围内所有的num,再遍历i,j,若有i * i - j * j == num,则num是special num,增加一个结果。

答案:1516

代码:

public class Main {

    private static int ti, tj;

    private static boolean isSpecial(int num) {
        int i = 1, j = 0;

        while(true) {
            int cur = i * i - j * j;
            if(cur == num) {
                ti = i;
                tj = j;
                return true;
            }
            if(cur < num) i++;	// cur太小
            if(cur > num) j++;	// cur太大

            if(j > 50000) break;
            if(i > 100000) break;
        }

        return false;
    }

    public static void main(String[] args) {
        int res = 0;
        for(int i = 1; i <= 2021; i++) {
            if(isSpecial(i)) {
                System.out.println(i + "=" + ti + "*" + ti + "-" + tj + "*" + tj);
                res++;
            }
        }
        System.out.println("res=" + res);
    }
}

第4题

小蓝要用01串来表达一段文字,这段文字包含 a, b, c, d, e, f 共 6 个字母,每个字母出现的次数依次为:a 出现 10 次,b 出现 20 次,c 出现 3 次,d 出现 4 次,e 出现 18 次,f 出现 50 次。
 小蓝准备分别对每个字母使用确定的01串来表示,不同字母的01串长度可以不相同。
 在表示文字时,将每个字母对应的01串直接连接起来组成最终的01串。为了能够正常还原出文字,小蓝的编码必须是前缀码,即任何一个字符对应的01串都不能是另一个字符对应的01串的前缀。
 例如,以下是一个有效的编码:
 a: 000
 b: 111
 c: 01
 d: 001
 e: 110
 f: 100
 其中 c 的长度为 2,其它字母的编码长度为 3,这种方式表示这段文字需要的总长度为:10*3+20*3+3*2+4*3+18*3+50*3=312
 上面的编码显然不是最优的,将上面的 f 的编码改为 10,仍然满足条件,但是总长度为 262,要短 50。
 要想编码后的总长度尽量小,应当让出现次数多的字符对应的编码短,出现次数少的字符对应的编码长。
 请问,在最优情况下,编码后的总长度最少是多少?

思路:哈夫曼树和哈夫曼编码,草稿纸上得出结果

答案:219

第5题

下面的矩阵中包含 ABCDEF 六种字符,请问出现最多的字符出现了几次?
 FFEEFEAAECFFBDBFBCDA
 DACDEEDCCFFAFADEFBBA
 FDCDDCDBFEFCEDDBFDBE
 EFCAAEECEECDCDECADDC
 DFAEACECFEADCBFECADF
 DFBAAADCFAFFCEADFDDA
 EAFAFFDEFECEDEEEDFBD
 BFDDFFBCFACECEDCAFAF
 EFAFCDBDCCBCCEADADAE
 BAFBACACBFCBABFDAFBE
 FCFDCFBCEDCEAFBCDBDD
 BDEFCAAAACCFFCBBAAEE
 CFEFCFDEEDCACDACECFF
 BAAAFACDBFFAEFFCCCDB
 FADDDBEBCBEEDDECFAFF
 CDEAFBCBBCBAEDFDBEBB
 BBABBFDECBCEFAABCBCF
 FBDBACCFFABEAEBEACBB
 DCBCCFADDCACFDEDECCC
 BFAFCBFECAACAFBCFBAF

思路:遍历字符串,为每个字符映射一个value,遇到一次,则value++。

答案:78

代码:

import java.util.HashMap;
import java.util.Map;

public class Main {
	private final static String STR = "FFEEFEAAECFFBDBFBCDA\r\n" + 
			"  DACDEEDCCFFAFADEFBBA\r\n" + 
			"  FDCDDCDBFEFCEDDBFDBE\r\n" + 
			"  EFCAAEECEECDCDECADDC\r\n" + 
			"  DFAEACECFEADCBFECADF\r\n" + 
			"  DFBAAADCFAFFCEADFDDA\r\n" + 
			"  EAFAFFDEFECEDEEEDFBD\r\n" + 
			"  BFDDFFBCFACECEDCAFAF\r\n" + 
			"  EFAFCDBDCCBCCEADADAE\r\n" + 
			"  BAFBACACBFCBABFDAFBE\r\n" + 
			"  FCFDCFBCEDCEAFBCDBDD\r\n" + 
			"  BDEFCAAAACCFFCBBAAEE\r\n" + 
			"  CFEFCFDEEDCACDACECFF\r\n" + 
			"  BAAAFACDBFFAEFFCCCDB\r\n" + 
			"  FADDDBEBCBEEDDECFAFF\r\n" + 
			"  CDEAFBCBBCBAEDFDBEBB\r\n" + 
			"  BBABBFDECBCEFAABCBCF\r\n" + 
			"  FBDBACCFFABEAEBEACBB\r\n" + 
			"  DCBCCFADDCACFDEDECCC\r\n" + 
			"  BFAFCBFECAACAFBCFBAF";
	
	
	public static void main(String[] args) {
		Map<Character, Integer> map = new HashMap<>();
		for(int i = 0; i < STR.length(); i++) {
			char ch = STR.charAt(i);
			if(ch == 'A' || ch == 'B' || ch == 'C' || ch == 'D' || ch == 'E' || ch == 'F') {
				if(!map.containsKey(ch)) {
					map.put(ch, 1);
				} else {
					map.put(ch, map.get(ch) + 1);
				}
			}
		}
		System.out.println(map.get('A'));
		System.out.println(map.get('B'));
		System.out.println(map.get('C'));
		System.out.println(map.get('D'));
		System.out.println(map.get('E'));
		System.out.println(map.get('F'));
	}
	
}

第6题

问题描述

小蓝要到店里买铅笔。
 铅笔必须一整盒一整盒买,一整盒 12 支,价格 p 元。
 小蓝至少要买 t 支铅笔,请问他最少花多少钱?

输入格式

输入一行包含两个整数 p、t,用一个空格分隔。

输出格式

输出一行包含一个整数,表示答案。

样例输入

5 30

样例输出

15

样例说明

小蓝至少要买3盒才能保证买到30支铅笔,总共花费 15 元。

评测用例规模与约定

对于所有评测用例,1 <= p <= 100,1 <= t <= 10000。

思路:设要买的盒数为n,则需要满足12n >=t,那么res = np;所以 n = ⌈ t / 12 ⌉ n = \lceil t / 12 \rceil n=t/12

代码:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int p = sc.nextInt();
        int t = sc.nextInt();

        int n = (int) Math.ceil(t / 12.0);	//计算出盒数
        System.out.println(n * p);	//计算总价
    }
}

第7题

问题描述

给定一个三角形的三条边的长度 a, b, c,请问这个三角形是不是一个直角三角形。

输入格式

输入一行包含三个整数 a, b, c,表示三角形三边的长度,相邻整数之间用一个空格分隔。

输出格式

如果是直角三角形,输出“YES”(全大写),否则输出“NO”(全大写)。

样例输入

3 4 5

样例输出

YES

样例输入

4 5 4

样例输出

NO

评测用例规模与约定

对于所有评测用例,1 <= a, b, c <= 1000。

思路:根据勾股定理来判断直角

代码:

import java.util.Scanner;

public class Main {
	
	//a,b是短边,c是长边
	private static boolean isRight(int a, int b, int c) {
		if(a * a + b * b == c * c) return true;
		else return false;
	}
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int a = sc.nextInt();
		int b = sc.nextInt();
		int c = sc.nextInt();
		
		Boolean res = false;
		if(a >= b && a >= c) {	// a最长
			res = isRight(b, c, a);
		} else if(b >= a && b >= c) {	// b最长
			res = isRight(a, c, b);
		} else {	// c最长
			res = isRight(a, b, c);
		}
		
		if(res) System.out.println("YES");
		else System.out.println("NO");
	}
}

第8题

问题描述

n 个小朋友正在做一个游戏,每个人要分享一个自己的小秘密。
 每个小朋友都有一个 1 到 n 的编号,编号不重复。
 为了让这个游戏更有趣,老师给每个小朋友发了一张卡片,上面有一个 1 到 n 的数字,每个数字正好出现一次。
 每个小朋友都将自己的秘密写在纸上,然后根据老师发的卡片上的数字将秘密传递给对应编号的小朋友。如果老师发给自己的数字正好是自己的编号,这个秘密就留在自己手里。
 小朋友们拿到其他人的秘密后会记下这个秘密,老师会再指挥所有小朋友将手中的秘密继续传递,仍然根据老师发的卡片上的数字将秘密传递给对应编号的小朋友。
 这样不断重复 n 次。
 现在,每个小朋友都记下了很多个秘密。
 老师现在想找一些小朋友,能说出所有秘密,请问老师最少要找几个小朋友?

输入格式

​ 输入的第一行包含一个整数 n。
第二行包含 n 个整数 a[1], a[2], …, a[n],相邻的整数间用空格分隔,分别表示编号 1 到 n 的小朋友收到的数字。

输出格式

输出一行包含一个整数,表示答案。

样例输入

6
2 1 3 5 6 4

样例输出

3

样例说明

最终小朋友 1, 2 互相知道了对方的秘密,小朋友 3 只知道自己的秘密,小朋友 4, 5, 6 互相知道了对方的秘密。
 至少要找 3 个小朋友才能说出所有秘密。

评测用例规模与约定

对于 30% 的评测用例,2 <= n <= 30。
 对于 60% 的评测用例,2 <= n <= 1000。
 对于所有评测用例,2 <= n <= 100000。

思路:为每个小朋友映射一个集合,集合里存的是他已经知道的秘密的序号(秘密所属小朋友的序号)。模拟一下,然后暴搜。

代码:

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

public class Main {
    private static int tn;
    private static int[] st = new int[100005];	//0表示还没选,1表示选了,2表示不选
    private static Map<Integer, Set<Integer>> tMap;
    private static int res = 0x3f3f3f3f;

    //指数型枚举,u从1开始
    private static void dfs(int u) {
        // 全部选完了
        if(u > tn) {
            // 取一波并集
            Set<Integer> mset = new HashSet<>();
            int count = 0;
            for(int i = 1; i <= tn; i++) {
                if(st[i] == 1) {
                    mset.addAll(tMap.get(i));
                    count++;
                }
            }
            // 全了
            if(mset.size() >= tn) {
                res = Math.min(res, count);
            }
            return;
        }

        //选这个位置
        st[u] = 1;
        dfs(u + 1);
        st[u] = 0;

        //不选这个位置
        st[u] = 2;
        dfs(u + 1);
        st[u] = 0;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] a = new int[n + 5];

        for(int i = 1; i <= n; i++) {
            a[i] = sc.nextInt();
        }

        Map<Integer, Set<Integer>> map = new HashMap<>();
        // 自己知道自己的秘密
        for(int i = 1; i <= n; i++) {
            Set<Integer> set = new HashSet<>();
            set.add(i);
            map.put(i, set);
        }

        // 把秘密传给对应同学
        for(int i = 0; i < n; i++) {	//传n次
            for(int j = 1; j <= n; j++) {	//对n个同学进行处理
                //a[j]号同学就知道j号同学知道的秘密
                Set<Integer> set = map.get(a[j]);	//获取到a[j]号同学的秘密集合
                set.addAll(map.get(j));	//j号同学的秘密加入到a[j]号同学的秘密集合
            }
        }

        // 暴力搜索什么样的组合能够知道所有的秘密
        // 变量全局化
        tMap = map;
        tn = n;
        dfs(1);
        System.out.println(res);
    }
}

第9题

问题描述

一个 1 到 n 的排列被称为半递增序列,是指排列中的奇数位置上的值单调递增,偶数位置上的值也单调递增。
 例如:(1, 2, 4, 3, 5, 7, 6, 8, 9) 是一个半递增序列,因为它的奇数位置上的值是 1, 4, 5, 6, 9,单调递增,偶数位置上的值是 2, 3, 7, 8,也是单调递增。
 请问,1 到 n 的排列中有多少个半递增序列?

输入格式

输入一行包含一个正整数 n。

输出格式

输出一行包含一个整数,表示答案,答案可能很大,请输出答案除以 1000000007 的余数。

样例输入

5

样例输出

10

样例说明

有以下半递增序列:
 (1, 2, 3, 4, 5)
 (1, 2, 3, 5, 4)
 (1, 2, 4, 3, 5)
 (1, 3, 2, 4, 5)
 (1, 3, 2, 5, 4)
 (1, 4, 2, 5, 3)
 (2, 1, 3, 4, 5)
 (2, 1, 3, 5, 4)
 (2, 1, 4, 3, 5)
 (3, 1, 4, 2, 5)

评测用例规模与约定

对于 50% 的评测用例,2 <= n <= 20。
 对于所有评测用例,2 <= n <= 1000。

思路:先暴力了再说

代码:

import java.util.Scanner;

public class Main {
	
	private static int n, res;
	private static int[] st = new int[1005];	//状态,0表示没放,1~n表示放了的数
	private static boolean[] used = new boolean[1005];
	
	private static void dfs(int u) {
	    if(u > n){
	    	boolean flag = true;
	        for(int i = 3; i <= n; i+=2 ){
	        	if(st[i] < st[i - 2]) {
	        		flag = false;
	        		break;
	        	}
	        }
	        for(int i = 4; i <= n; i+=2) {
	        	if(st[i] < st[i - 2]) {
	        		flag = false;
	        		break;
	        	}
	        }
	        if(flag == true) res++;
	        return;
	    }
	    //枚举当前位置能够填的数
	    for(int i = 1; i <= n; i++ ){
	        if(!used[i]){
	            st[u] = i;
	            used[i] = true;
	            dfs(u + 1);
	            used[i] = false;
	        }
	    }
	}
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		dfs(1);
		System.out.println(res);
	}
}

感谢宜宾学院黄诗宇同学提供的题解

import java.util.Arrays;
import java.util.Scanner;

/**
 * Created by IntelliJ IDEA.
 * User: ShiYu Huang
 * Date: 2021-11-28
 */
public class I {
    static int N = 1010, M = N / 2;
    static int[][] f = new int[N][N];
    static int ans = 0;
    static final int p =1000000000+7;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = (n + 1) / 2;
        f[0][0] = 1;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                for (int k = j - 1; k <= i - 1; k++) {
                    f[i][j] = (f[i][j]+f[k][j - 1])%p;
                }
            }
        }
        ans = (ans+f[n][m])%p;
        if (n % 2 == 0) {
            ans = (ans*2)%p;
        } else {
            for (int i = 0; i < f.length; i++) {
                Arrays.fill(f[i], 0);
            }
            m = n - m;
            f[0][0] = 1;
            for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= m; j++) {
                    for (int k = j - 1; k <= i - 1; k++) {
                        f[i][j] =(f[i][j]+f[k][j - 1])%p;
                    }
                }
            }
            ans=(ans+f[n][m])%p;
        }
        System.out.println(ans);
    }
}

第10题

问题描述

小蓝住在 LQ 城,今天他要去小乔家玩。
 LQ 城可以看成是一个 n 行 m 列的一个方格图。
 小蓝家住在第 1 行第 1 列,小乔家住在第 n 行第 m 列。
 小蓝可以在方格图内走,他不愿意走到方格图外。
 城市中有的地方是风景优美的公园,有的地方是熙熙攘攘的街道。小蓝很喜欢公园,不喜欢街道。他把方格图中的每一格都标注了一个属性,或者是喜欢的公园,标为1,或者是不喜欢的街道标为2。小蓝和小乔住的地方都标为了1。
 小蓝每次只能从一个方格走到同一行或同一列的相邻方格。他想找到一条路径,使得不连续走两次标为 2 的街道,请问在此前提下他最少要经过几次街道?

输入格式

输入的第一行包含两个整数 n, m,用一个空格分隔。
 接下来 n 行,每行一个长度为 m 第数字串,表示城市的标注。

输出格式

输出一行包含一个整数,表示答案。如果没有满足条件的方案,输出 -1。

样例输入

3 4
1121
1211
2211

样例输出

2

样例输入

3 4
1122
1221
2211

样例输出

-1

样例输入

5 6
112121
122221
221212
211122
111121

样例输出

5

评测用例规模与约定

对于 50% 的评测用例,2 <= n, m <= 20。
 对于所有评测用例,2 <= n, m <= 300。

思路:dfs 搜一遍

代码:

import java.util.Scanner;

public class Main {
    private static final int INF = 0x3f3f3f3f;
    private static int n, m, res = INF;
    private static int[][] map = new int[305][305];
    private static boolean[][] st = new boolean[305][305];

    private final static int[][] next = {
            {-1, 0}, {0, 1}, {1, 0}, {0, -1}
    };

    private static void dfs(int x, int y, int count) {  //count记录已经走过的街道的数量
        if(x == n - 1 && y == m - 1) {
            // 到终点了
            res = Math.min(res, count);
            return;
        }

        st[x][y] = true;
        for(int i = 0; i < 4; i++) {
            int tx = x + next[i][0];
            int ty = y + next[i][1];

            if(tx < 0 || tx >= n || ty < 0 || ty >= m) continue;
            if(st[tx][ty]) continue;
            if(map[tx][ty] == 2 && map[x][y] == 2) continue;

            dfs(tx, ty, map[x][y] == 2 ? count + 1 : count);
        }
        st[x][y] = false;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();

        for(int i = 0; i < n; i++) {
            String line = sc.next();
            for(int j = 0; j < m; j++) {
                int ch = line.charAt(j);
                int cur = ch - '0';
                map[i][j] = cur;
            }
        }
        dfs(0, 0, 0);
        if(res == INF) res = -1;
        System.out.println(res);
    }
}
  • 11
    点赞
  • 89
    收藏
    觉得还不错? 一键收藏
  • 24
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值