2019省赛真题详解

组队

作为篮球队教练,你需要从以下名单中选出 1 号位至 5 号位各一名球员, 组成球队的首发阵容。
每位球员担任 1 号位至 5 号位时的评分如下表所示。请你计算首发阵容 1 号位至 5 号位的评分之和最大可能是多少?
在这里插入图片描述
这题手算即可,但是还是给出代码运算也行
两种解决方法
1.暴力破解法,直接嵌套5层for循环
2.贪心算法,每次选择当前位最高的人,保存总和,三次for循环,以不同位置起手结果不同,所以首层遍历5次位置,二层选出其他号位号位的最高成绩,3层选出本号位最高的选手.

不同的子串

一个字符串的非空子串是指字符串中长度至少为 1 的连续的一段字符组成 的串。例如,字符串aaab 有非空子串a, b, aa, ab, aaa, aab, aaab,一共 7 个。 注意在计算时,只算本质不同的串的个数。 请问,字符串0100110001010001 有多少个不同的非空子串?

  1. 本题按位分解即可,使用set去重

数列求值

给定数列1, 1, 1, 3, 5, 9, 17, …,从第4 项开始,每项都是前3 项的和。求
第20190324 项的最后4 位数字

一开始使用暴力结果很大,存不下.
题目说也就是说4位之外的数字我们都不管,就直接舍弃

 public static void main(String[] args) {
        int a = 1, b = 1, c = 1;
        for (int i = 3; i < 20190324; i++) {
            //也就是说4位之外的数字我们都不管,就直接舍弃,
            int index = (a + b + c) % 10000;
            a = b;
            b = c;
            c = index;
        }
        System.out.println(c);
    }

数的分解

把2019 分解成3 个各不相同的正整数之和,并且要求每个正整数都不包
含数字2 和4,一共有多少种不同的分解方法?
注意交换3 个整数的顺序被视为同一种方法,例如1000+1001+18 和
1001+1000+18 被视为同一种。

一开始想的是暴力破解,从1到2019建立3个循环,但是衍生出重复的情况,一开始设想建立比较器进行判断,但是3的n次方量太大.后来想到,如果一开始建立序列即可,根据范围求解
i: 可以为任何数
b:范围则 i+1~(2019-i+1) ,加一是因为数组for循环从0开始,加一弥补实例上的b能到达循环2018的情况,
c: **范围则为2019-i-b **,其实使用for循环也行,但是会浪费太多时间

分成3个范围,此时就不会出现重复的情况
加上题目给的条件即可

//判断题目的条件
public static boolean textNum(int i){
        //处理 2,20 200 2000
        if (i/100==2||i/10==2||i/1000==2||i%1000==2
         ||i%100==2||i%10==2||i==2)return  false;
       //处理 1200,1120
        int n=i%1000;//比如 293
        if(n<300&&n>199) return false;
        if(n<500&&n>399) return false;
        n=i%100;
        if(n<30&&n>19) return false;
        if(n<50&&n>39) return false;
        if (i/100==4||i/10==4||i%1000==4
                ||i%100==4||i%10==4||i==4)return  false;
        return true;
    }
//主方法
public static void ada(int nums){
      //按照范围即可
        int count=0;
        for (int i=1;i<nums;i++){
            if (!textNum(i)) continue;
            for (int b=i+1;b<(nums-i+1)/2;b++){
                if(textNum(b)){
                    int c=nums-i-b;
                  //  if (textNum(c)&&i!=b&&i!=c&&b!=c){\
                    if (textNum(c)&&c!=i&&c!=b){
                        //去除重复
                        count++;
                        }
                }

            }

        }
        System.out.println(count);

    }

5.迷宫:

题目不在赘述,一开始的想法便是 要么动态规划,回溯,要么就是广度优先算法, 一步一步试探进行,然后不行再回溯.

6 特别数的和

小明对数位中含有 2、0、1、9 的数字很感兴趣(不包括前导 0),在 1 到 40 中这样的数包括 1、2、9、10 至 32、39 和 40,共 28 个,他们的和是 574。

请问,在 1 到 n 中,所有这样的数的和是多少?

 public static void sadaad(int n){
        //
        int count=0;
        for (int i=1;i<=n;i++){
            String s=i+"";
            if (s.contains("2")||s.contains("1")||
            s.contains("9")||s.contains("0")) count+=i;
        }
        System.out.println(count);
    }

7.外卖店优先级

饱了么”外卖系统中维护着 N 家外卖店,编号 1 ∼ N。每家外卖店都有 一个优先级,初始时 (0 时刻) 优先级都为 0。 每经过 1 个时间单位,如果外卖店没有订单,则优先级会减少 1,最低减 到 0;而如果外卖店有订单,则优先级不减反加,每有一单优先级加 2。 如果某家外卖店某时刻优先级大于 5,则会被系统加入优先缓存中;如果 优先级小于等于 3,则会被清除出优先缓存。 给定 T 时刻以内的 M 条订单信息,请你计算 T 时刻时有多少外卖店在优先缓存中。
给出的信息

第一行包含 3 个整数 N、M 和 T。 以下 M 行每行包含两个整数 ts 和 id,表示 ts 时刻编号 id 的外卖店收到 一个订单。
【输出格式】
输出一个整数代表答案。
【样例输入】
2 6 6
1 1
5 2
3 1
6 2
2 1
6 2
【样例输出】
1
【样例解释】
6 时刻时,1 号店优先级降到 3,被移除出优先缓存;2 号店优先级升到 6, 加入优先缓存。所以是有 1 家店 (2 号) 在优先缓存中。

解题思路,看着题目长长的,实际不难解决
1.第一步是先存放好店铺的id,拿到M行下的数组里的店铺id,先暂存到一个Set集合中,防止店铺重复

//按照题目生成的方法
  public static int elm(int n,int m,int t,int [][] oreder){
 Set<Integer> ids = new HashSet<Integer>();
        for(int i = 0; i < m;i++) {
            ids.add(oreder[i][1]);
        }
  1. 根据店铺的id开始遍历表中的数据,我们对于每个店铺都是单独进行处理.根据比对店铺id与订单表中的id进行比对,将相关的时间ts单独存放再一个ArrayList中, 先大小排序,防止时间短的再后面
 for (int userid:ids){
            //当前店铺的订单
            List<Integer> temp=new ArrayList<>();
          //  int[] aa=new int[m];
            for(int i = 0; i < m; i++) {
                if(oreder[i][1] == userid) {
               //     aa[i]=oreder[i][0];//保存订单的时间
                    temp.add(oreder[i][0]); //保存订单的时间
                }
            }
            //开始计算店铺优先级
            int nowLeven=0;
            //比较订单大小,有小到大排序
         //    Arrays.sort(aa);
            Collections.sort(temp);//使用比较器进行排序
           // ====for (int userid:ids)未结束====
            }
  1. 开始计算优先级,然而题目中存在两个同样的订单,所以对于多个一样的订单,我先遍历看看有没有一样的订单再进行其余的计算.
for(int ts = 1; ts <= t; ts++) {
                //时间开始计算
                    if (temp.contains(ts)) {
                        //当前时间有订单
                        for (int w = 0; w < temp.size(); w++) {
                            //判断是否包含多个订单,如果含有多个则快速进行排序
                            if (temp.get(w) == ts) {
                                nowLeven += 2;
                            } else if (temp.get(w) > ts) {
                                break;//推出循环
                            } else {
                                continue;
                            }
                        }
	//for循环------未结束
  1. 接下来计算优先级就行,初始化为0, int nowLeven=0;,当大于5是进入缓存中,小与3则移除,我用一个set进行存储就行优先缓存就行,然后继续进行时间片的计算
  2. 最后输出优先缓存的大小即可
public static int elm(int n,int m,int t,int [][] oreder){
        //id集合,用来存放商家的id号

        Set<Integer> dianCaChe = new HashSet<Integer>();

        Set<Integer> ids = new HashSet<Integer>();
        for(int i = 0; i < m;i++) {
            ids.add(oreder[i][1]);
        }
        //遍历订单,给每位店铺计算一次时间
        for (int userid:ids){
            //当前店铺的订单
            List<Integer> temp=new ArrayList<>();
          //  int[] aa=new int[m];
            for(int i = 0; i < m; i++) {
                if(oreder[i][1] == userid) {
               //     aa[i]=oreder[i][0];//保存订单的时间
                    temp.add(oreder[i][0]); //保存订单的时间
                }
            }
            //开始计算店铺优先级
            int nowLeven=0;
            //比较订单大小,有小到大排序
         //    Arrays.sort(aa);
            Collections.sort(temp);//使用比较器进行排序
            for(int ts = 1; ts <= t; ts++) {
                //时间开始计算
                    if (temp.contains(ts)) {
                        //当前时间有订单
                        for (int w = 0; w < temp.size(); w++) {
                            //判断是否包含多个订单,如果含有多个则快速进行排序
                            if (temp.get(w) == ts) {
                                nowLeven += 2;
                            } else if (temp.get(w) > ts) {
                                break;//推出循环
                            } else {
                                continue;
                            }
                        }
                        //判断是否可以加入缓存
                        if (nowLeven > 5) {
                            dianCaChe.add(userid);
                            System.out.println("====添加id为" + userid + "的店铺");
                        }
                    } else {//当前没有订单
                            if (nowLeven>=1)
                            {nowLeven--;}
                            else {
                                nowLeven=0;
                            }
                            if(nowLeven<=3){
                                dianCaChe.remove(userid);
                                System.out.println("清除id为"+userid+"的店铺");
                            }
                        }
                    }
            }
        //结束根据id存储用户的比较
        System.out.println("最终剩余的店铺数量为:"+dianCaChe.size());
         return dianCaChe.size();
    }

代码很长,但是不难理解.

剩下的有空再写

【问题描述】

小明正在分析一本小说中的人物相关性。他想知道在小说中 Alice 和 Bob 有多少次同时出现。 更准确的说,小明定义 Alice 和 Bob“同时出现”的意思是:在小说文本 中 Alice 和 Bob 之间不超过 K 个字符。 例如以下文本: ThisisastoryaboutAliceandBob.AlicewantstosendaprivatemessagetoBob.
假设 K = 20,则 Alice 和 Bob 同时出现了 2 次,分别是”Alice and Bob” 和”Bob. Alice”。前者 Alice 和 Bob 之间有 5 个字符,后者有 2 个字符。
注意:
1.Alice 和 Bob 是大小写敏感的,alice 或 bob 等并不计算在内。
2.Alice 和 Bob 应为单独的单词,前后可以有标点符号和空格,但是不能有字母。例如 Bobbi 并不算出现了 Bob。

判断是否包含完事了

 public static int  getFunction(String people,int maxCode){
        //拿到了语句
         //根据空格切割语句
         String[] allWord=people.split("\\s+|\\.");
            //此时按照空格和多个标点符号切割了字符串
         int[] wordLength=new int[allWord.length];
         for (int i = 0; i < allWord.length; i++) {
             wordLength[ i]=allWord[i].length();
         }
         //遍历拿到每个字符串的长度
        int count=0;//记录人数
         //开始比对情况,
         for (int k = 0; k < allWord.length; k++) {
         if(allWord[k].equals("Alice")){
            for (int w=k+1;w< allWord.length;w++){
                int strSum=1;//Alice之后的空格数为1
                if(allWord[w].equals("Bob")){
                    //找到当前的W,到w即for循环停止
                    for (int q = k + 1;q <w; q++) {
                        // 每个单词的长度加空格占据的长度
                        strSum += wordLength[q] + 1;
                    }
                    if(strSum<=maxCode) count++;
                }
            }
         }
         }
            //重复一次
         for (int k = 0; k < allWord.length; k++) {
             if(allWord[k].equals("Bob")){
                 for (int w=k+1;w< allWord.length;w++){
                     int strSum=1;//Alice之后的空格数为1
                     if(allWord[w].equals("Alice")){
                         //找到当前的W,到w即for循环停止
                         for (int q = k + 1; q <w; w++) {
                             // 每个单词的长度加空格占据的长度,所以加一
                             strSum += wordLength[q] + 1;
                         }
                         if(strSum<=maxCode) count++;
                     }
                 }
             }
         }
         System.out.println(count);
     return count;
     }

9.后缀表达式

【问题描述】
给定 N 个加号、M 个减号以及 N + M + 1 个整数 A1,A2,··· ,AN+M+1,小 明想知道在所有由这 N 个加号、M 个减号以及 N + M +1 个整数凑出的合法的 后缀表达式中,结果最大的是哪一个?
请你输出这个最大的结果。 例如使用1 2 3 + -,则 “2 3 + 1 -” 这个后缀表达式结果是 4,是最大的。
【输入格式】
第一行包含两个整数 N 和 M。 第二行包含 N + M + 1 个整数 A1,A2,··· ,AN+M+1。
【输出格式】
输出一个整数,代表答案。
【样例输入】
1 1
1 2 3
【样例输出】
4

这里一题使出全部情况即可,但是我写的繁杂
列出3种情况

  1. 当减号小与0 的时候,将数组就相加就行

  2. 当加号少于0的时候,出现两种细微的情况
    2.1 出现全部正数:
    例如:[1,2,3,4,5,6] 加号:0,减去:5
    6-(1-2-3-4-5)=19 最大的减去-(最小的数-第二小的数…)
    利用正负转换的,拿到最大数
    2.2 出现负数
    含有负数: [-3,1,2,3,4] 加号:0,减号:4
    4-3-2-1+3=1 ,显然不是最大的,
    4-(-3-1-2-3)=4+9=13

  3. 出现减号和加号
    3.1 减号>=负数的个数
    例如 [-2, -1, 1, 2, 3],两个减号两个加号
    运算过程为 3 - (-1) - (-2) + 1 + 2,
    即每个减号匹配一个负数将其变正,然后从大到小累加这些数,再减去和剩下的减号数量相等的数

    3.2 减<负数的个数:
    例如 [-2,-1,1],一个加号一个减号,运算过程为 1 - (-2 + -3)
    即把负数相加来消除负数,这时候有两种情况

        3.2.2 全是负数,如 [-1, -2, -3, -4, -5],一个加号三个减号
          	运算过程为 -1 - ( -4 + -5 ) - (-3) - (-2)
      		即首先排序选择其中的最大值,加上其他数字的绝对值就行。 
      	3.2.2 有正数,有负数,如 [-4,-3,-2,-1,1],两个加号两个减号
                  运算过程为 1 - ( -4 + -3 + -2 + -1 ) - -1
                 即首先排序选择其中的最大值,加上其他数字的绝对值就行。
    

    按照以上情形解决就行

public  static int getMaxNum(int add ,int reduce ,int[] number ){
  
			int num = add + reduce + 1;//数
			int sum = 0;
			if (reduce == 0) {//1
				for (int i = 0; i < num; i++) {
					sum += number[i];
				}
			}
			if (add == 0) {//2
				Arrays.sort(number);
				if (number[0] < 0) {//2.1
					for (int i = 0; i <= reduce; i++) {
						if (number[i] > 0) 
							sum += number[i];
						else
							sum -= number[i];
					}
				} else {//2.2
					for (int i = 1; i <= reduce; i++) {
							sum += number[i];
					}
					sum -= number[0];
				}
			}
			//3. 第三的情况
			if (add != 0 && reduce != 0) {//3
				int negativeNumber = 0;//负数
				for (int i = 0; i < num; i++) {
					if (number[i] < 0) {
						negativeNumber++;
					}
				}
				Arrays.sort(number);
				if (reduce >= negativeNumber) {//3.1
					int temp = reduce;
					for (int i = 0; i < negativeNumber; i++) {
						number[i] = -number[i];
						temp--;
					}
					Arrays.sort(number);
					for (int i = num - 1; i >= temp; i--) {
						sum += number[i];
					}
					for (int i = temp - 1; i >= 0; i--) {
						sum -= number[i];
					}
				} else {//3.2
					sum += number[num - 1];
					for (int i = 0; i < num - 1; i++) {
						if (number[i] > 0)
							sum += number[i];
						else
							sum -= number[i];
					}
				}
			}
			System.out.println(sum);
			sc.close();
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值