javaB组国赛真题

javaB组国赛真题

2021年第十二届真题

试题A: 整数范围

本题总分:5 分
【问题描述】

用8位二进制(一个字节)来表示一个非负整数,表示的最小值是0,则一般能表示的最大值是多少?

【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

解:

2 8 ^8 8-1=255

试题B: 纯质数

本题总分:5 分
【问题描述】

如果一个正整数只有1和它本身两个约数,则称为一个质数(又称素数)。
  前几个质数是:2,3,5,7,11,13,17,19,23,29,31,37…。
  如果一个质数的所有十进制数位都是质数,我们称它为纯质数。例如:2,3,5,7,23,37都是纯质数,而11,13,17,19,29,31不是纯质数。当然1,4,35也不是纯质数。
  请问,在1到20210605中,有多少个纯质数?

【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

解题思路:

1、找到1~20210605所有的质数

2、判断是不是纯质数

判断质数的方法

public static boolean isPrime(int n){
    if (n <= 3) {
        return n > 1;
    }
    for(int i = 2; i*i < n; i++){
        if (n % i == 0) {
            return false;
        }
    }
    return true;
}
public static boolean check(int number) {
    int flag = 0;//设置一个标志

    if (number == 1 || number == 0) {//此方法用于排除1和0的影响
        return false;//返回false
    }
    for (int i = 2; i < number; i++) {//用一个for循环
        if (number % i == 0) {
            flag = 1;
            break;
        }
    }
    if (flag == 1) {//标志处理
        return false;
    } else {
        return true;
    }
}

试题C: 完全日期

本题总分:10 分
【问题描述】

如果一个日期中年月日的各位数字之和是完全平方数,则称为一个完全日期。
  例如:2021年6月5日的各位数字之和为2 + 0 + 2 + 1 + 6 + 5 = 16,而16是一个完全平方数,它是4的平方。所以2021年6月5日是一个完全日期。
  例如:2021年6月23日的各位数字之和为2 + 0 + 2 + 1 + 6 + 2 + 3 = 16,是一个完全平方数。所以2021年6月23日也是一个完全日期。
  请问,从2001年1月1日到2021年12月31日中,一共有多少个完全日期?

【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

本题思路很简单,就是暴力枚举,但是用Java的话要熟悉Canlendar类的使用,这样不容易出错

最后还是要复习一下Calendar类

//指定输入格式
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyy/MM/dd");
//获取指定日期的Data对象
Date date = simpleDateFormat.parse("2001/01/01");//parse解析
//        System.out.println(date.toString());
//创建一个calendar对象,以便后面利用里面的方法?
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
//        System.out.println(calendar.toInstant());//2000-12-31T16:00:00Z
calendar.add(Calendar.DAY_OF_YEAR, 1);//获取后相差了一天,把它加回去
//    System.out.println(calendar.toInstant());//2001-01-01T16:00:00Z

 calendar.add(Calendar.DAY_OF_MONTH,1);//加的是每个月的一天!

总结下一下如何使用calendar,首先创建一个输入格式,在输入指定日期,创建一个data,将这个data传进calendar中,即可。

这样就可以利用calendar的add方法对日期进行加减了,会自动识别不需要自己判断闰年,大小月。

试题D: 最小权值

本题总分:10 分
【问题描述】

对于一棵有根二叉树T,小蓝定义这棵树中结点的权值W(T)如下:
  空子树的权值为0。
  如果一个结点v有左子树L,右子树R,分别有C(L)和C®个结点,则:
    W(v) = 1 + 2W(L) + 3W® +(C(L))2C®。
  树的权值定义为树的根结点的权值。
  小蓝想知道,对于一棵有2021个结点的二叉树,树的权值最小可能是多少?

【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

  1. dp数组含义:存放各节点的最小权值
  2. dp[0]=0;dp[1]=1;初始化值
  3. dp公式:可以根据题目推出
  4. 遍历顺序:从节点数量1~2021
  5. 距离推导

DP模板

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组
#模板
dp=[]*(n+1)                             #1.dp数组初始化      
dp[x]=[]                                #2.特殊值赋值
for i in range():                       #3.循环遍历
  for j in range():
    dp[j]=min(dp[j],dp[i]+abc(i,j))     #4.递推公式
print(dp[n])                            #5.打印数组		

试题E: 大写

时间限制: 1.0s  内存限制: 512.0MB  本题总分:15分
【问题描述】

给定一个只包含大写字母和小写字母的字符串,请将其中所有的小写字母转换成大写字母后将字符串输出。

【输入格式】
输入一行包含一个字符串
【输出格式】
输出转换成大写后的字符串。
【样例输入1】
LanQiao
【样例输出1】
LANQIAO
【评测用例规模与约定】
对于所有评测用例,字符串的长度不超过100。

public class q5大写 {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        String small = scanner.next();
        String s = small.toUpperCase();
        System.out.println(s);
    }
}

试题F: 123

时间限制: 5.0s   内存限制: 512.0MB   本题总分:15分
【问题描述】

小蓝发现了一个有趣的数列,这个数列的前几项如下:
    1, 1, 2, 1, 2, 3, 1, 2, 3, 4, …
  小蓝发现,这个数列前1项是整数1,接下来2项是整数1至2,接下来3项是整数1至3,接下来4项是整数1至4,依次类推。
  小蓝想知道,这个数列中,连续一段的和是多少。

【输入格式】
输入的第一行包含一个整数T,表示询问的个数。
接下来T行,每行包含一组询问,其中第i行包含两个整数li和ri,表示询问数列中第li个数到第ri个数的和。
【输出格式】
输出T行,每行包含一个整数表示对应询问的答案。
【样例输入】
3
1 1
1 3
5 8
【样例输出】
1
4
8
【评测用例规模与约定】

在这里插入图片描述

首先关于本题,没有优化思路的情况下,建议直接模拟

最简单的模拟,记录所有查询中最大的下标,然后去构造同样长度的序列,再求数组的累加和。(纯正的模拟)

稍微优化的做法

前缀和

试题G:和与成绩

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hB4XEMzy-1677812888194)(G:/CS/PROJECT/蓝桥杯/蓝桥杯国赛/补充算法/历年真题/笔记Img/image-20220529193313021.png)]

在这里插入图片描述

DP算法

参考了几个博客找到,本题还是使用DP算法:

#模板
dp=[]*(n+1)                             #1.dp数组初始化      
dp[x]=[]                                #2.特殊值赋值
for i in range():                       #3.循环遍历
  for j in range():
    dp[j]=min(dp[j],dp[i]+abc(i,j))     #4.递推公式
print(dp[n])                            #5.打印数组		

1.初始化 \2.赋初值

//DP:1.初始化数组
for (int i =1; i <=n; i++) {
    for (int j =i; j <=n; j++) {
        if (i==j){
            dp[i][j][0]=list1[i];
            dp[i][j][1]=list1[i];
        }
    }
}

3.遍历 \4.递推公式

for (int i = 1; i <=n ; i++) {
    for (int j = i+1; j <=n ; j++) {
        dp[i][j][0]=dp[i][j-1][0]+list1[j];
        dp[i][j][1]=dp[i][j-1][1]*list1[j];
    }
}

5.输出res

for (int i = 1; i <=n ; i++) {
    for (int j = i+1; j <=n ; j++) {
        if (dp[i][j][0]==dp[i][j][1]){
            ans++;
        }
    }
}
System.out.println(ans);

完整代码:

package _2021;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Scanner;
 
public class Q7和与乘积 {
    static int dp[][][]=new int[102][102][2];
    static  int list1 []=new int[202];
    static  int n;
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        n=sc.nextInt();//数组长度
        for (int i = 1; i <= n; i++) {
            list1[i]=sc.nextInt();
        }
//        for (int i : list1) {
//            System.out.print(i+" ");
//        }
        //DP:1.初始化数组
        for (int i =1; i <=n; i++) {
            for (int j =i; j <=n; j++) {
                if (i==j){
                    dp[i][j][0]=list1[i];
                    dp[i][j][1]=list1[i];
                }
            }
        }
        int ans=n;

        for (int i = 1; i <=n ; i++) {
            for (int j = i+1; j <=n ; j++) {
                dp[i][j][0]=dp[i][j-1][0]+list1[j];
                dp[i][j][1]=dp[i][j-1][1]*list1[j];
            }
        }

        for (int i = 1; i <=n ; i++) {
            for (int j = i+1; j <=n ; j++) {
                if (dp[i][j][0]==dp[i][j][1]){
                    ans++;
                }
            }
        }
        System.out.println(ans);

    }

}

试题H: 巧克力

时间限制: 1.0s    内存限制: 512.0MB    本题总分:20分
【问题描述】

小蓝很喜欢吃巧克力,他每天都要吃一块巧克力。
  一天小蓝到超市想买一些巧克力。超市的货架上有很多种巧克力,每种巧克力有自己的价格、数量和剩余的保质期天数,小蓝只吃没过保质期的巧克力,
  请问小蓝最少花多少钱能买到让自己吃x天的巧克力。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6KPrXj0O-1677812888195)(G:/CS/PROJECT/蓝桥杯/蓝桥杯国赛/补充算法/历年真题/笔记Img/image-20220529193453350.png)]

10 3

1 6 5

2 7 3

3 10 10

考虑一种贪心算法,将所有巧克力按照价格从小到大重新排列,然后枚举每一个巧克力,根据保质期和数量进行判断,同时要注意,这X天,每天只要有一个巧克力就行,为避免重复,我们使用boolean[] have数组记录当天是否有巧克力吃

再遍历巧克力的同时,记录能够满足巧克力的天数,和其花费,最后比较这个天数是否为题目要求的X天如果是,这直接输出花费,否则输出-1;

类排序

package _2021;

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

public class q8巧克力 {
    public static void main(String[] args) {
        int  x,n;
        int[][] choise;
        Scanner sc=new Scanner(System.in);
        x=sc.nextInt();//需要吃巧克力的天数
        n=sc.nextInt();//巧克力的种类
        choise=new int[n][3];
        for (int i = 0; i < n; i++) {
            choise[i][0]=sc.nextInt();//单价
            choise[i][1]=sc.nextInt();//保质期
            choise[i][2]=sc.nextInt();//数量
        }
//        for (int[] ints : choise) {
//            for (int anInt : ints) {
//                System.out.print(anInt+" ");
//            }
//            System.out.println("");
//        }

        int day=0;//记录能吃的天数
        int money=0;//记录最小花费
        //对类进行排序,贪心所在!
        Arrays.sort(choise, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[0]-o2[0];//数量
            }
        });
        //记录这一天是否有巧克力吃
        boolean [] have=new boolean[x+1];
        //遍历所有巧克力
        for (int[] c : choise) {
            //用have数组避免重复购买!
            while (c[1]>0&&c[2]>0){//这一个巧克力进行循环,当它的保质期代表的天数没有下降时,就是一天,所以要have数组为false的那一天才能计算进去,否则就是重复
                if (have[c[1]]==false){//
                    have[c[1]]=true;
                    c[2]--;
                    day++;
                    money+=c[0];
                }
            }
        }
        System.out.println(day==x?money:-1);
    }
}

试题I:翻转括号序列

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lzj4XJ7d-1677812888195)(G:/CS/PROJECT/蓝桥杯/蓝桥杯国赛/补充算法/历年真题/笔记Img/image-20220529193521029.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OTfZfmO7-1677812888196)(G:/CS/PROJECT/蓝桥杯/蓝桥杯国赛/补充算法/历年真题/笔记Img/image-20220529193528987.png)]

待定

试题J:异或三角

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ANJvIylD-1677812888196)(G:/CS/PROJECT/蓝桥杯/蓝桥杯国赛/补充算法/历年真题/笔记Img/image-20220529193815675.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gBypWF7h-1677812888196)(G:/CS/PROJECT/蓝桥杯/蓝桥杯国赛/补充算法/历年真题/笔记Img/image-20220529193834237.png)]

待定

2020

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A6P8YMUa-1677812888197)(https://output-course-file.oss-cn-hangzhou.aliyuncs.com/courses%2F2786%2Fattachments%2F1621305714442%2F1.png?OSSAccessKeyId=LTAI5tSaDTdU7mDrbH3Z1k5C&Expires=1654679332&Signature=9nDP5kecy9FfQ2PvZjf%2FPK9Veqg%3D)]

1.美丽的二

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dmu6hNHV-1677812888197)(https://output-course-file.oss-cn-hangzhou.aliyuncs.com/courses%2F2786%2Fattachments%2F1621305714442%2F2.png?OSSAccessKeyId=LTAI5tSaDTdU7mDrbH3Z1k5C&Expires=1654679332&Signature=GExcj6Mkys2pAbrsVSBvdyR6NhU%3D)]

package q2022;

import org.junit.jupiter.api.Test;

public class q1美丽的二 {
    @Test
    public void test1(){
        String a=12+" ";
        System.out.println(a);
    }
    public static void main(String[] args) {
        int num=0;
        for (int i = 1; i <=2020 ; i++) {
            String a=i+" ";
            if (a.contains("2")) num++;
        }
        System.out.println(num);
    }
}

2.扩散

BFS

package q2022;

import java.util.LinkedList;

public class q2扩散 {
    //本题使用BFS,用一个队列存放黑点,每取出一个点,判断其上下左右是否是黑色,如果是则不用加入队列,否则变黑加入队列
    //ps:可以将这几个点的横纵坐标都加上3000,因为扩散2020分钟相当于走了2020步
    /*
    细节,这个队列是一个index类,为什么?-->方便进行方向的变化,更能代表这个点的信息。
    +3000,把x,y都变成正的,不会出现复数的情况,因为二维数组的下标不可能是负的啊
     */
    //x,y
    static int [][] move={{1,0},{-1,0},{0,1},{0,-1}};//表示移动方向:右左上下

    public static void main(String[] args) {
        int [][] arr=new int[8000][8000];//判断矩阵
        LinkedList <index> queue=new LinkedList<>();//存放队列
        queue.add(new index(3000,3000,0));
        queue.add(new index(5020,3011,0));
        queue.add(new index(3011,3014,0));
        queue.add(new index(5000,5000,0));

        int cnt=4;//黑点数量
        arr[3000][3000]=1;
        arr[5020][3011]=1;
        arr[3011][3014]=1;
        arr[5000][5000]=1;

        while (!queue.isEmpty()){
            index poll = queue.poll();
            int time= poll.time;
            if (time==2020){break;}
            int x=poll.x;
            int y=poll.y;
            for (int i = 0; i < move.length; i++) {
                int x2=x+move[i][0];//左右变化
                int y2=y+move[i][1];//上下变化
                if (arr[x2][y2]==0){
                    queue.add(new index(x2,y2,time+1));
                    arr[x2][y2]=1;
                    cnt++;
                }
            }
        }
        System.out.println(cnt);
    }

}
class index{
    int x;
    int y;
    int time;

    public index(int x, int y, int time) {
        this.x = x;
        this.y = y;
        this.time = time;
    }

    @Override
    public String toString() {
        return "index{" +
                "x=" + x +
                ", y=" + y +
                ", time=" + time +
                '}';
    }
}

3.阶乘约数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9LzGbsfe-1677812888198)(https://output-course-file.oss-cn-hangzhou.aliyuncs.com/courses%2F2786%2Fattachments%2F1621305714442%2F4.png?OSSAccessKeyId=LTAI5tSaDTdU7mDrbH3Z1k5C&Expires=1654679332&Signature=siecKrp71exKztg0YfAdq1uhUsM%3D)]

算术基本定理

初等数论

本题考察的是算术基本定理,即给定一个数n,求得n以内的约束个数,此外需要注意的地方是,100的阶乘比较大,这里使用的是BigInteger。

算数基本原理模板

 static int factors(long n) {
        int res = 1, now;
        for (int i = 2; i * i <= n; i++) {//首先找到小于根号n的所有质数,
            now = 1;
            while (n % i == 0) {
                n /= i;
                now++;
            }
            if (now > 1)
                res *= now;
        }
        return n > 1? res *2 : res;
    }

本题题解

package q2022;
import java.math.BigInteger;

public class q3阶乘约数 {

/*
BigInterge小课堂
**A compareTo (B)**
if A>B return 1
if A=B return 0
if A<b return -1
判断是否相等===》equal

**加减乘除**
add 、substract、mutiply、divide
 */

private static BigInteger getNumber(BigInteger t){//基本算数定理,求数n的公约数
    BigInteger ans = BigInteger.ONE;
    BigInteger one = BigInteger.ONE;
    for(BigInteger i=new BigInteger("2");i.multiply(i).compareTo(t)<=0;i=i.add(one)){
        BigInteger mos = BigInteger.ONE;
        while (t.mod(i).compareTo(BigInteger.ZERO)==0){
            t=t.divide(i);//除法
            mos=mos.add(BigInteger.ONE);
        }
        if (mos.compareTo(BigInteger.ONE)>0 ) ans=ans.multiply(mos);
    }
    return t.compareTo(BigInteger.ONE)>0?ans.multiply(new BigInteger("2")):ans;
}

    private static BigInteger getnumber(BigInteger t)
    {
        BigInteger ans=BigInteger.ONE;
        BigInteger one = BigInteger.ONE;
        for (BigInteger i = new BigInteger("2"); i.multiply(i).compareTo(t)<=0 ; i=i.add(one)) {
            BigInteger mos=BigInteger.ONE;
            while(t.mod(i).compareTo(BigInteger.ZERO)==0)
            {
                t=t.divide(i);
                mos=mos.add(BigInteger.ONE);
            }
            if(mos.compareTo(BigInteger.ONE)>0) ans=ans.multiply(mos);
        }
        return t.compareTo(BigInteger.ONE)>0?ans.multiply(new BigInteger("2")):ans;
    }

    public static void main(String[] args) {
        BigInteger s = BigInteger.ONE;
        for (int i = 1; i <=100; i++) {
            s=s.multiply(new BigInteger(i+""));
        }
//        System.out.println(getnumber(s));
        System.out.println(getNumber(s));
    }
}

4.本质上升序列

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cQxKg5Jp-1677812888198)(https://output-course-file.oss-cn-hangzhou.aliyuncs.com/courses%2F2786%2Fattachments%2F1621305714442%2F5.png?OSSAccessKeyId=LTAI5tSaDTdU7mDrbH3Z1k5C&Expires=1654679332&Signature=E7jQi7%2FOOd%2FvNnrbh4EXg4OT9Y4%3D)]

详见

https://www.bilibili.com/video/BV11b4y1o7sq?spm_id_from=333.337.search-card.all.click

主要使用了dp递推

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PclpySWG-1677812888199)(G:/CS/PROJECT/蓝桥杯/蓝桥杯国赛/补充算法/历年真题/2020年真题Img/image-20220608194402999.png)]

package q2022;

import org.junit.jupiter.api.Test;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class q4本质上生序列 {
    //dp递推
        public static void main(String[] args) throws IOException {
            BufferedReader bf = new BufferedReader(new FileReader("G:\\CS\\PROJECT\\蓝桥杯\\蓝桥杯国赛\\lqb\\src\\main\\java\\q2022\\inc.txt"));//读文件
            String [] arr=new String[4];
            String t="";
            int cur=0;
            while((t=bf.readLine())!=null)
            {
                arr[cur++]=t;
            }
            int [][]dp=new int[205][26];
            cur=1;
            char [] ms=new char[205];
            for (int i = 0; i < arr.length; i++) {
                for (int j = 0; j < arr[i].length(); j++) {
                    ms[cur]=arr[i].charAt(j);
                    dp[cur++][arr[i].charAt(j)-'a']=1;
                }
            }
            for (int i = 2; i <= 200; i++) {
                char nowchr=ms[i];
                for (int j = 0; j < nowchr-'a'; j++) {
                    dp[i][nowchr-'a']+=dp[i-1][j];
                }
                for (int j = 0; j < 26; j++) {
                    if(j==nowchr-'a') continue;
                    dp[i][j]=dp[i-1][j];
                }
            }
            int cnt=0;
            for (int i = 0; i < 26; i++) {
                cnt+=dp[200][i];
            }
            System.out.println(cnt);
        }


        @Test
    public  void dp_method(){
            String a="tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl";
            char[] s = a.toCharArray();
            long []dp=new long[200];
            int i;
            for (i=0;i<200;i++){
                dp[i]+=1;
                int q;
                for (q=i-1;q>-1;q--){
                    if (s[q]==s[i]){
                        dp[i]--;
                        break;
                    }
                    if (s[i]>s[q]){dp[i]+=dp[q];}
                }
            }
            int sum=0;
            int j;
            for ( j = 0; j < 200; j++) {
                sum+=dp[j];
//                System.out.println(j);
            }
//            System.out.println(dp.length);
            System.out.println(sum);
            //3616159
        }
}

5.玩具蛇

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9n85ttbH-1677812888199)(https://output-course-file.oss-cn-hangzhou.aliyuncs.com/courses%2F2786%2Fattachments%2F1621305714442%2F6.png?OSSAccessKeyId=LTAI5tSaDTdU7mDrbH3Z1k5C&Expires=1654679332&Signature=ZbAedDzS17HRbYTZrNlWPR5YzL8%3D)]

6.蓝肽子序列

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XeHFtefJ-1677812888200)(https://output-course-file.oss-cn-hangzhou.aliyuncs.com/courses%2F2786%2Fattachments%2F1621305714442%2F7.png?OSSAccessKeyId=LTAI5tSaDTdU7mDrbH3Z1k5C&Expires=1654679332&Signature=22VV8voHg8eCXXvbnHIrbuLiGWA%3D)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Loco3IRc-1677812888200)(https://output-course-file.oss-cn-hangzhou.aliyuncs.com/courses%2F2786%2Fattachments%2F1621305714442%2F8.png?OSSAccessKeyId=LTAI5tSaDTdU7mDrbH3Z1k5C&Expires=1654679332&Signature=9%2BHCHG2YK3lcIIz%2FtQnGqQqG9OU%3D)]

参考题解

比较好的思路可以结合LCS一起看

https://blog.csdn.net/lishuaigell/article/details/123697786

https://blog.csdn.net/qq_53763705/article/details/123683929

DP系列学习

参考视频:

https://www.bilibili.com/video/BV1vz4y1Z7oM?spm_id_from=333.999.0.0

别人做的题目

刷完真题再说

https://blog.csdn.net/lishuaigell/category_11672995.html

本题可以参考LCS最长公共子序列

给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符n串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。

示例 1:

输入:text1 = “abcde”, text2 = “ace”
输出:3
解释:最长公共子序列是 “ace” ,它的长度为 3 。

https://leetcode.cn/problems/longest-common-subsequence/

7.皮亚诺曲线距离

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XWmHgld2-1677812888201)(https://output-course-file.oss-cn-hangzhou.aliyuncs.com/courses%2F2786%2Fattachments%2F1621305714442%2F9.png?OSSAccessKeyId=LTAI5tSaDTdU7mDrbH3Z1k5C&Expires=1654679332&Signature=UCm86%2Bj9sOtyXakIjO0OLSDP%2FwM%3D)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OoQYyvXT-1677812888201)(https://output-course-file.oss-cn-hangzhou.aliyuncs.com/courses%2F2786%2Fattachments%2F1621305714442%2F10.png?OSSAccessKeyId=LTAI5tSaDTdU7mDrbH3Z1k5C&Expires=1654679332&Signature=yI2e6Clhz5r7HmO13hL9JUPtVLM%3D)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OfVj2t6s-1677812888201)(https://output-course-file.oss-cn-hangzhou.aliyuncs.com/courses%2F2786%2Fattachments%2F1621305714442%2F11.png?OSSAccessKeyId=LTAI5tSaDTdU7mDrbH3Z1k5C&Expires=1654679332&Signature=s20athkurHrFWzo0Z4PNkbqQlG4%3D)]

8.画廊

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xublJYh4-1677812888202)(https://output-course-file.oss-cn-hangzhou.aliyuncs.com/courses%2F2786%2Fattachments%2F1621305714442%2F12.png?OSSAccessKeyId=LTAI5tSaDTdU7mDrbH3Z1k5C&Expires=1654679332&Signature=ijisho5JC%2F1iACwvqL7RSp3Q7wQ%3D)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zQ4xKdIM-1677812888202)(https://output-course-file.oss-cn-hangzhou.aliyuncs.com/courses%2F2786%2Fattachments%2F1621305714442%2F13.png?OSSAccessKeyId=LTAI5tSaDTdU7mDrbH3Z1k5C&Expires=1654679332&Signature=4OfL3sIOgWAbPSg74Rli8fwXHhE%3D)]

9.补给

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kS2ovylX-1677812888202)(https://output-course-file.oss-cn-hangzhou.aliyuncs.com/courses%2F2786%2Fattachments%2F1621305714442%2F14.png?OSSAccessKeyId=LTAI5tSaDTdU7mDrbH3Z1k5C&Expires=1654679332&Signature=UdeyilgDkslYHM3s%2BsjQdUUPxj8%3D)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1jT4Duzj-1677812888203)(https://output-course-file.oss-cn-hangzhou.aliyuncs.com/courses%2F2786%2Fattachments%2F1621305714442%2F15.png?OSSAccessKeyId=LTAI5tSaDTdU7mDrbH3Z1k5C&Expires=1654679332&Signature=s7yd0q0bV1GdzT0KJwJQlA30PCY%3D)]

10.质数行者

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FhHdy77L-1677812888203)(https://output-course-file.oss-cn-hangzhou.aliyuncs.com/courses%2F2786%2Fattachments%2F1621305714442%2F16.png?OSSAccessKeyId=LTAI5tSaDTdU7mDrbH3Z1k5C&Expires=1654679332&Signature=xlobae2TCSwMtKqPA70CcE617EA%3D)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dbI6Jy3Y-1677812888203)(https://output-course-file.oss-cn-hangzhou.aliyuncs.com/courses%2F2786%2Fattachments%2F1621305714442%2F17.png?OSSAccessKeyId=LTAI5tSaDTdU7mDrbH3Z1k5C&Expires=1654679332&Signature=DFwBvpaXmvcQJLhkzETnXUCsXw4%3D)]

2019年蓝桥杯国赛真题

A:递增序列(难度:★★)

对于一个字母矩阵,我们称矩阵中的一个递增序列是指在矩阵中找到两个字母,它们在同一行,同一列,或者在同一 45 度的斜线上,这两个字母从左向右看、或者从上向下看是递增的。

例如,如下矩阵中
LANN
QIAO
有LN、LN、AN、AN、IO、AO、LQ、AI、NO、NO、AQ、IN、AN 等 13 个递增序列。注意当两个字母是从左下到右上排列时,从左向右看和从上向下看是不同的顺序。

对于下面的 30 行 50 列的矩阵,请问总共有多少个递增序列?(如果你把以下文字复制到文本文件中,请务必检查复制的内容是否与文档中的一致。在试题目录下有一个文件 inc.txt,内容与下面的文本相同。

VLPWJVVNNZSWFGHSFRBCOIJTPYNEURPIGKQGPSXUGNELGRVZAG
SDLLOVGRTWEYZKKXNKIRWGZWXWRHKXFASATDWZAPZRNHTNNGQF
ZGUGXVQDQAEAHOQEADMWWXFBXECKAVIGPTKTTQFWSWPKRPSMGA
BDGMGYHAOPPRRHKYZCMFZEDELCALTBSWNTAODXYVHQNDASUFRL
YVYWQZUTEPFSFXLTZBMBQETXGXFUEBHGMJKBPNIHMYOELYZIKH
ZYZHSLTCGNANNXTUJGBYKUOJMGOGRDPKEUGVHNZJZHDUNRERBU
XFPTZKTPVQPJEMBHNTUBSMIYEGXNWQSBZMHMDRZZMJPZQTCWLR
ZNXOKBITTPSHEXWHZXFLWEMPZTBVNKNYSHCIQRIKQHFRAYWOPG
MHJKFYYBQSDPOVJICWWGGCOZSBGLSOXOFDAADZYEOBKDDTMQPA
VIDPIGELBYMEVQLASLQRUKMXSEWGHRSFVXOMHSJWWXHIBCGVIF
GWRFRFLHAMYWYZOIQODBIHHRIIMWJWJGYPFAHZZWJKRGOISUJC
EKQKKPNEYCBWOQHTYFHHQZRLFNDOVXTWASSQWXKBIVTKTUIASK
PEKNJFIVBKOZUEPPHIWLUBFUDWPIDRJKAZVJKPBRHCRMGNMFWW
CGZAXHXPDELTACGUWBXWNNZNDQYYCIQRJCULIEBQBLLMJEUSZP
RWHHQMBIJWTQPUFNAESPZHAQARNIDUCRYQAZMNVRVZUJOZUDGS
PFGAYBDEECHUXFUZIKAXYDFWJNSAOPJYWUIEJSCORRBVQHCHMR
JNVIPVEMQSHCCAXMWEFSYIGFPIXNIDXOTXTNBCHSHUZGKXFECL
YZBAIIOTWLREPZISBGJLQDALKZUKEQMKLDIPXJEPENEIPWFDLP
HBQKWJFLSEXVILKYPNSWUZLDCRTAYUUPEITQJEITZRQMMAQNLN
DQDJGOWMBFKAIGWEAJOISPFPLULIWVVALLIIHBGEZLGRHRCKGF
LXYPCVPNUKSWCCGXEYTEBAWRLWDWNHHNNNWQNIIBUCGUJYMRYW
CZDKISKUSBPFHVGSAVJBDMNPSDKFRXVVPLVAQUGVUJEXSZFGFQ
IYIJGISUANRAXTGQLAVFMQTICKQAHLEBGHAVOVVPEXIMLFWIYI
ZIIFSOPCMAWCBPKWZBUQPQLGSNIBFADUUJJHPAIUVVNWNWKDZB
HGTEEIISFGIUEUOWXVTPJDVACYQYFQUCXOXOSSMXLZDQESHXKP
FEBZHJAGIFGXSMRDKGONGELOALLSYDVILRWAPXXBPOOSWZNEAS
VJGMAOFLGYIFLJTEKDNIWHJAABCASFMAKIENSYIZZSLRSUIPCJ
BMQGMPDRCPGWKTPLOTAINXZAAJWCPUJHPOUYWNWHZAKCDMZDSR
RRARTVHZYYCEDXJQNQAINQVDJCZCZLCQWQQIKUYMYMOVMNCBVY
ABTCRRUXVGYLZILFLOFYVWFFBZNFWDZOADRDCLIRFKBFBHMAXX

【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

分析:
枚举每一个坐标,对每个坐标枚举两字母的距离,
另外,每两个字母的方位只有四个情况:
情况一,两个字母在同一行
在此种情况下,当右边字母大于左边字母即可计数+1
情况二:两个字母在同一列
在此种情况下,当下边字母大于上边字母即可计数+1
情况三:一个字母在另一个字母的右下方
在此种情况下,从上向下看和从左向右看答案是相同的,当右下方字母大于左上方字母即可计数+1
情况四:一个字母在另一个字母的右上方
在此种情况下,从上向下看和从左向右看答案是相反的,所以我们只需要要求两字母不同即可计数+1

AC代码:
答案:52800

B:平方拆分(难度:★).

【问题描述】
将 2019 拆分为若干个两两不同的完全平方数之和,一共有多少种不同的方法?
注意交换顺序视为同一种方法,例如 13^2 + 25^2 + 35^2 = 2019 与 13^2 + 35^2 +25^2 = 2019 视为同一种方法。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

分析:
深搜解决,将已选元素放入list容器,记录当前最大元素cur,记录剩余需要拼合的和n。
不断递归迭代调用即可
当运行到出口即为答案。

最终答案需要*2;因为结果集中不包含0,在每个不包含0的结果集中加一个0又是一种全新的集合
如:13 25 35
和 0 13 25 35
是两个不同的组合

AC代码:
答案为:52574

解法一:使用DFS和剪枝来进行计算

https://blog.csdn.net/qq_39445165/article/details/111511762?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165493401916781818738380%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=165493401916781818738380&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-2-111511762-null-null.142^v13^pc_search_result_control_group,157^v14^new_3&utm_term=%E5%B9%B3%E6%96%B9%E6%8B%86%E5%88%86&spm=1018.2226.3001.4187
package q2019;

public class q2 {
    static int ans=0;
    static void  dfs(int minn,int maxx,int num) {
        if (num<0) return;
        if (num==0){
            ans++;
            return;
        }
        for (int i=minn;i<maxx;i++){
            dfs(i+1,maxx,num-i*i);
        }
    }
    public static void main(String[] args) {
        dfs(0,45,2019);
        //2019的平方根范围是 [0~45) ,直接深搜,只要保证平方根递增就不会有重复的情况出现。这里有个坑,0是完全平方数,所以要从0开始深搜。
        System.out.println(ans);
        }
}

使用动态规划来求解

package q2019;

import org.junit.jupiter.api.Test;

import java.util.Arrays;

public class q2 {
    static int ans = 0;

    static void dfs(int minn, int maxx, int num) {
        if (num < 0) return;
        if (num == 0) {
            ans++;
            return;
        }
        for (int i = minn; i < maxx; i++) {
            dfs(i + 1, maxx, num - i * i);
        }
    }

    public static void main(String[] args) {
        dfs(0, 45, 2019);
        //2019的平方根范围是 [0~45) ,直接深搜,只要保证平方根递增就不会有重复的情况出现。这里有个坑,0是完全平方数,所以要从0开始深搜。
        System.out.println(ans);
    }


    @Test
    public void test() {
        /*
                                0 1 4 9 16 25....
第一种只有0的情况      0(1)
              1                  0(1) 1(1)
               4                 0(1) 1(1)4(1) 5(1)
                 9               0(1) 1(1)4(1) 5(1)9(1) 10(1) 13(1)14(1)
                   16            0(1) 1(1)4(1) 5(1)9(1) 10(1) 13(1)14(1)16(1) 17(1)20(1)21(1)25(1)26(1)29(1) 30(1)
                      25         0(1) 1(1)4(1) 5(1)9(1) 10(1) 13(1)14(1)16(1) 17(1)20(1)21(1)25(2)26(1)29(1) 30(1)......
         */
        //定义一个数组存放可能的值
        int[] ffs = new int[2019 + 1];
        ffs[0]=1;//初始化
        for (int i = 0; i * i <= 2019; i++) {
            for (int w = 2019; w - i * i >= 0; w--) {
                if (ffs[w - i * i] != 0) {
                    ffs[w] += ffs[w - i * i];
                }
            }
        }
        System.out.println(ffs[2019]);
    }

}

C:切割(难度:★★).

【问题描述】
在 4 × 4 的方格矩阵中画一条直线。则直线穿过的方格集合有多少种不同的
可能?
这个里直线穿过一个方格当且仅当直线将该方格分割成面积都大于 0 的两
部分。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分

分析:
AC代码:

无!

D:最优旅行(难度:★★★).

【问题描述】
中国的高铁四通八达,乘坐方便,小明经常乘坐高铁在城市间旅游。
现在,小明又有了一个长假,他打算继续乘坐高铁旅游。这次,他打算到
下面的城市旅游。
上海、广州、长沙、西安、杭州、济南、成都、南京、昆明、郑州、天津、
太原、武汉、重庆、南昌、长春、沈阳、贵阳、福州。
小明打算从北京出发,游览以上每个城市正好一次,最终回到北京。在每
个城市(除北京外),小明都至少停留 24 小时。而当小明决定从一个城市去往
另一个城市时,他只会选择有直接高铁连接的城市,不会在中途换乘转车。
在试题目录下有一个文件 trip.txt 保存了小明可以选择的车次,小明不会
选择其他车次。
小明出发的时间是第 1 天的中午 12:00。请问,小明游览完以上城市正好一
次,最终回到北京,最快需要多少分钟(请注意单位为分钟,请注意除北京外
的城市需要至少停留 24 小时,即最少停留 1440 分钟)。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

分析:
AC代码:

https://blog.csdn.net/qq_43319748/article/details/109647178?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165493590116782350920228%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=165493590116782350920228&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-109647178-null-null.142^v13^pc_search_result_control_group,157^v14^new_3&utm_term=%E6%9C%80%E4%BC%98%E6%97%85%E8%A1%8C&spm=1018.2226.3001.4187

https://blog.csdn.net/weixin_44190072/article/details/115584303

E:序列求和(难度:★★★★).

【问题描述】
学习了约数后,小明对于约数很好奇,他发现,给定一个正整数 t,总是可
以找到含有 t 个约数的整数。小明对于含有 t 个约数的最小数非常感兴趣,并
把它定义为 S t 。
例如 S 1 = 1, S 2 = 2, S 3 = 4, S 4 = 6,· · · 。
现在小明想知道,前 60 个 S i 的和是多少?即 S 1 + S 2 + · · · + S 60 是多少?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

分析:
我们先用一个Map储存键值对<约数个数,值>,
然后遍历一百万左右数据,填充大部分位置
对于质数项,只能是2的(质数-1)次幂,填充少部分位置
对于剩余项,直接求合数即可。

AC代码:
答案是正确的

  1. 给一个数求其约束的个数,判断其个数
  2. 求和

超时了!!

F:最长子序列(难度:★★★★★).

【问题描述】
我们称一个字符串 S 包含字符串 T 是指 T 是 S 的一个子序列,即可以从
字符串 S 中抽出若干个字符,它们按原来的顺序组合成一个新的字符串与 T 完
全一样。
给定两个字符串 S 和 T,请问 T 中从第一个字符开始最长连续多少个字符
被 S 包含?
【输入格式】
输入两行,每行一个字符串。第一行的字符串为 S,第二行的字符串为 T。
两个字符串均非空而且只包含大写英文字母。
【输出格式】
输出一个整数,表示答案。
【样例输入】
ABCDEABCD
AABZ
【样例输出】
3
【评测用例规模与约定】
对于 20% 的评测用例,1 ≤ |T| ≤ |S | ≤ 20;
对于 40% 的评测用例,1 ≤ |T| ≤ |S | ≤ 100;
对于所有评测用例,1 ≤ |T| ≤ |S | ≤ 1000。

分析:
思路很简单,从头到尾遍历串S,遇到与 t[p] 相同的 p++ 即可,
最终运行结束 p就是答案

G:数正方形(难度:★★★★★

【问题描述】
在一个 N × N 的点阵上,取其中 4 个点恰好组成一个正方形的 4 个顶点,
一共有多少种不同的取法?
由于结果可能非常大,你只需要输出模 109 + 7 的余数。

如上图所示的正方形都是合法的。
【输入格式】
输入包含一个整数 N。
【输出格式】
输出一个整数代表答案。
【样例输入】
4
【样例输出】
20
【数据规模与约定】
对于所有评测用例,2 ≤ N ≤ 1000000。

package JAVA2019;

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

public class H大胖子走迷宫 {
	public static boolean ok=false;
	public static int n,k,r=2,time=0;
	public static char c[][];
	public static boolean vis[][];
	public static ArrayList<Integer> cur=new ArrayList<Integer>();
	public static ArrayList<Integer> next=new ArrayList<Integer>();
	public static boolean check(int x,int y,int i,int j){
		if(Math.abs(i+j)!=1)return false;
		if(x+i<0||x+i>=n||y+j<0||y+j>=n)return false;
		if(vis[x+i][y+j])return false;
		for(int a=x+i-r;a<=x+i+r;a++){
			for(int b=y+j-r;b<=y+j+r;b++){
				if(a<0||b<0||a>=n||b>=n||c[a][b]=='*'){
					return false;
				}
			}
		}
		return true;
	}
	public static void BFS(){
		if(time>=k&&time<2*k)r=1;
		else if(time>=2*k)r=0;
		int x=-1,y=-1;
		for(int t:cur){
			x=t/10000;
			y=t%10000;
			next.add(t);
			for(int i=-1;i<2;i++){
				for(int j=-1;j<2;j++){
					if(check(x, y, i, j)){
						next.add((x+i)*10000+y+j);
						vis[x+i][y+j]=true;
						if(x+i==n-3&&y+j==n-3)ok=true;
					}
				}
			}
		}
		cur.clear();
		cur.addAll(next);
		next.clear();
		time++;
	}
	public static void main(String[] args) {
		Scanner scanner=new Scanner(System.in);
		n=scanner.nextInt();
		k=scanner.nextInt();
		c=new char[n][n];
		vis=new boolean [n][n];
		vis[2][2]=true;
		for(int i=0;i<n;i++){
			c[i]=scanner.next().toCharArray();
		}
		cur.add(20002);
		while(!ok){
			BFS();
		}
		System.out.println(time);
	}
}

H:大胖子走迷宫(难度:★★★★★).

【问题描述】
小明是个大胖子,或者说是个大大胖子,如果说正常人占用 1 × 1 的面积,
小明要占用 5 × 5 的面积。
由于小明太胖了,所以他行动起来很不方便。当玩一些游戏时,小明相比
小伙伴就吃亏很多。
小明的朋友们制定了一个计划,帮助小明减肥。计划的主要内容是带小明
玩一些游戏,让小明在游戏中运动消耗脂肪。走迷宫是计划中的重要环节。
朋友们设计了一个迷宫,迷宫可以看成是一个由 n × n 个方阵组成的方阵,
正常人每次占用方阵中 1 × 1 的区域,而小明要占用 5 × 5 的区域。小明的位置
定义为小明最正中的一个方格。迷宫四周都有障碍物。
为了方便小明,朋友们把迷宫的起点设置在了第 3 行第 3 列,终点设置在
了第 n n 2 行第 n n 2 列。
小明在时刻 0 出发,每单位时间可以向当前位置的上、下、左、右移动单
位 1 的距离,也可以停留在原地不动。小明走迷宫走得很辛苦,如果他在迷宫
里面待的时间很长,则由于消耗了很多脂肪,他会在时刻 k 变成一个胖子,只
占用 3 × 3 的区域。如果待的时间更长,他会在时刻 2k 变成一个正常人,只占
用 1 × 1 的区域。注意,当小明变瘦时迷宫的起点和终点不变。
请问,小明最少多长时间能走到迷宫的终点。注意,小明走到终点时可能
变瘦了也可能没有变瘦。
【输入格式】
输入的第一行包含两个整数 n, k。
接下来 n 行,每行一个由 n 个字符组成的字符串,字符为 + 表示为空地,
字符为 * 表示为阻碍物。
【输出格式】
输出一个整数,表示答案。
【样例输入】

9 5
+++++++++
+++++++++
+++++++++
+++++++++
+++++++++
***+*****
+++++++++
+++++++++
+++++++++

【样例输出】
16
【评测用例规模与约定】
对于 30% 的评测用例,1 ≤ n ≤ 50。
对于 60% 的评测用例,1 ≤ n ≤ 100。
对于所有评测用例,1 ≤ n ≤ 300,1 ≤ k ≤ 1000。

分析:
采用BFS的思路就很简单,胖子有五种移动可能,分别是上下左右和原地不动,
对每种情况进行检查,是否符合移动条件,当到达终点即结束BFS

AC代码:

package JAVA2019;

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

public class H大胖子走迷宫 {
	public static boolean ok=false;
	public static int n,k,r=2,time=0;
	public static char c[][];
	public static boolean vis[][];
	public static ArrayList<Integer> cur=new ArrayList<Integer>();
	public static ArrayList<Integer> next=new ArrayList<Integer>();
	public static boolean check(int x,int y,int i,int j){
		if(Math.abs(i+j)!=1)return false;
		if(x+i<0||x+i>=n||y+j<0||y+j>=n)return false;
		if(vis[x+i][y+j])return false;
		for(int a=x+i-r;a<=x+i+r;a++){
			for(int b=y+j-r;b<=y+j+r;b++){
				if(a<0||b<0||a>=n||b>=n||c[a][b]=='*'){
					return false;
				}
			}
		}
		return true;
	}
	public static void BFS(){
		if(time>=k&&time<2*k)r=1;
		else if(time>=2*k)r=0;
		int x=-1,y=-1;
		for(int t:cur){
			x=t/10000;
			y=t%10000;
			next.add(t);
			for(int i=-1;i<2;i++){
				for(int j=-1;j<2;j++){
					if(check(x, y, i, j)){
						next.add((x+i)*10000+y+j);
						vis[x+i][y+j]=true;
						if(x+i==n-3&&y+j==n-3)ok=true;
					}
				}
			}
		}
		cur.clear();
		cur.addAll(next);
		next.clear();
		time++;
	}
	public static void main(String[] args) {
		Scanner scanner=new Scanner(System.in);
		n=scanner.nextInt();
		k=scanner.nextInt();
		c=new char[n][n];
		vis=new boolean [n][n];
		vis[2][2]=true;
		for(int i=0;i<n;i++){
			c[i]=scanner.next().toCharArray();
		}
		cur.add(20002);
		while(!ok){
			BFS();
		}
		System.out.println(time);
	}
}

I:估计人数(难度:★★★★★).

【问题描述】
给定一个 N × M 的方格矩阵,矩阵中每个方格标记 0 或者 1 代表这个方格
是不是有人踩过。
已知一个人可能从任意方格开始,之后每一步只能向右或者向下走一格。
走了若干步之后,这个人可以离开矩阵。这个人经过的方格都会被标记为 1,
包括开始和结束的方格。注意开始和结束的方格不需要一定在矩阵边缘。
请你计算至少有多少人在矩阵上走过。
【输入格式】
输入第一行包含两个整数 N、M。
以下 N 行每行包含 M 个整数 (0/1),代表方格矩阵。
【输出格式】
输出一个整数代表答案。
【样例输入】
5 5
00100
11111
00100
11111
00100
【样例输出】
3
【数据规模与约定】
对于所有评测用例,1 ≤ N, M ≤ 20,标记为 1 的方格不超过 200 个。

分析:
大佬说是匈牙利算法,没看懂,反正AC了

AC代码:

import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;

public class Main {

	static int V = 1;
	static int source[];
	static boolean graph[][], marked[];
	
    public static void main(String[] args) {
        InputReader in = new InputReader(System.in);
        int n = in.nextInt(), m = in.nextInt();
        int idx[][] = new int[n + 1][m + 1];
        for (int i = 0; i < n; i++)
        	for (int j = 0; j < m; j++)
        		 if (in.split() == '1')
        			idx[i][j] = V++;
        graph = new boolean[V][V];
        marked = new boolean[V];
        source = new int[V];
        for (int i = 0, v; i < n; i++)
        	for (int j = 0; j < m; j++)
        		if (idx[i][j] > 0) {
        			v = idx[i][j];
        			if (idx[i + 1][j] > 0)
        				graph[v][idx[i + 1][j]] = true;
        			if (idx[i][j + 1] > 0)
        				graph[v][idx[i][j + 1]] = true;
        		}
        for (int k = 1; k < V; k++)
        	for (int i = 1; i < V; i++)
        		for (int j = 1; j < V; j++)
        			graph[i][j] |= graph[i][k] & graph[k][j];
        int cnt = 0;
        for (int i = 1; i < V; i++) {
        	Arrays.fill(marked, false);
        	cnt += dfs(i)? 1: 0;
        }
        System.out.print(V - cnt - 1);
    }

    static boolean dfs(int v) {
    	for (int i = 1; i < V; i++) {
    		if (graph[v][i]) {
    			if (marked[i]) continue;
    			marked[i] = true;
    			if (source[i] == 0 || dfs(source[i])) {
    				source[i] = v;
    				return true;
    			}
    		}
    	}
    	return false;
    }
    
    static class InputReader {

        InputStream in;
        int next, len;
        byte[] buff;

        InputReader(InputStream in) { this(in, 8192); }

        InputReader(InputStream in, int buffSize) {
            this.buff = new byte[buffSize];
            this.next = this.len = 0;
            this.in = in;
        }

        int getByte() {
            if (next >= len)
                try {
                    next = 0;
                    len = in.read(buff);
                    if (len == -1) return -1;
                } catch (IOException e) {
                    e.fillInStackTrace();
                }
            return buff[next++];
        }

        int split() {
            int c = getByte();
            while (c <= 32 || c == 127) c = getByte();
            return c;
        }

        int nextInt() {
            int n = 0, c = split();
            boolean flag = true;
            if (c == '-') {
                c = getByte();
                flag = false;
            }
            while (c >= '0' && c <= '9') {
                n = n * 10 + (c & 0xf);
                c = getByte();
            }
            return flag? n: -n;
        }
    }
}

J:分考场(难度:★★★★★).

【问题背景】
古语有云:春风得意马蹄疾,一日看尽长安花。
当然在一场考试中所有人都春风得意马蹄疾是不可能的,尤其是碰到一些
毒瘤出题人的时候。
【问题描述】
又到了每月一次的月考,又是 xf 老师出题。
上一次 xf 老师出的题太毒瘤了,平均分只有 40 多,同学们都非常不满意,
毕竟别的科的平均分都是 80 多。
这次 xf 为了不被同学们寄刀片,想了一个办法:只公布所有考场的平均分
的平均分。这样他就可以通过调整考场的分配方式,使得平均分显得高。(每个
考场都可以容纳无限人)
每次考试也不是所有同学都参加的,只有学号在 [l,r] 这个区间中的同学会
参加。
他想知道对于每次考试,他调整过考场后,所有考场的平均分的平均分的
最大值。
当然,同学们也可能会努力学习或整日颓废使成绩发生改变。
【输入格式】
输入的第一行包含一个整数 n。
第二行包含 n 个整数,第 i 个数 vi,表示开始时每个同学的成绩。
第三行包含一个整数 q,表示有 q 次操作。
之后 q 行,每行描述一个操作,第一个数表示操作类型。
如果操作为 1 p x,表示学号为 p 的同学分数变为 x。
如果操作为 2 l r k, 表示把学号在 [l,r] 中的同学分成 k 个考场,求这 k 个
考场的平均分的平均分的最大值。
【输出格式】
对于每个 2 操作输出一行,四舍五入保留正好 3 位小数。
【样例输入】
5
5 3 4 2 1
5
2 1 4 3
1 4 8
2 3 5 3
1 2 2
2 1 3 2
【样例输出】
3.833
4.333
4.000
【样例说明】
第一个操作询问学号在 [1, 4] 之间的同学分成 3 个考场的平均分的平均分
的最大值,最优策略是:{1}, {2, 4}, {3},平均分是在这里插入图片描述

第二个操作把学号为 4 的同学的分数变为 8。
第三个操作询问学号在 [3, 5] 之间的同学分成 3 个考场的平均分的平均分
的最大值,最优策略是:{3}, {4}, {5}。
第四个操作把学号为 2 的同学分数变为 2。
第五个操作询问学号在 [1, 3] 之间的同学分成 2 个考场的平均分的平均分
的最大值,最优策略是:{1}, {2 3}。
【评测用例规模与约定】
对于全部评测用列,n ≤ 200000, q ≤ 200000, 任意时刻同学的分数 vi ≤ 10^9, k ≤ r - l+ 1。
评测时将使用 10 个评测用例测试你的程序,每个评测用例的限制如下:

lit() {
int c = getByte();
while (c <= 32 || c == 127) c = getByte();
return c;
}

    int nextInt() {
        int n = 0, c = split();
        boolean flag = true;
        if (c == '-') {
            c = getByte();
            flag = false;
        }
        while (c >= '0' && c <= '9') {
            n = n * 10 + (c & 0xf);
            c = getByte();
        }
        return flag? n: -n;
    }
}

}






## J:分考场(难度:★★★★★).

【问题背景】
古语有云:春风得意马蹄疾,一日看尽长安花。
当然在一场考试中所有人都春风得意马蹄疾是不可能的,尤其是碰到一些
毒瘤出题人的时候。
【问题描述】
又到了每月一次的月考,又是 xf 老师出题。
上一次 xf 老师出的题太毒瘤了,平均分只有 40 多,同学们都非常不满意,
毕竟别的科的平均分都是 80 多。
这次 xf 为了不被同学们寄刀片,想了一个办法:只公布所有考场的平均分
的平均分。这样他就可以通过调整考场的分配方式,使得平均分显得高。(每个
考场都可以容纳无限人)
每次考试也不是所有同学都参加的,只有学号在 [l,r] 这个区间中的同学会
参加。
他想知道对于每次考试,他调整过考场后,所有考场的平均分的平均分的
最大值。
当然,同学们也可能会努力学习或整日颓废使成绩发生改变。
【输入格式】
输入的第一行包含一个整数 n。
第二行包含 n 个整数,第 i 个数 vi,表示开始时每个同学的成绩。
第三行包含一个整数 q,表示有 q 次操作。
之后 q 行,每行描述一个操作,第一个数表示操作类型。
如果操作为 1 p x,表示学号为 p 的同学分数变为 x。
如果操作为 2 l r k, 表示把学号在 [l,r] 中的同学分成 k 个考场,求这 k 个
考场的平均分的平均分的最大值。
【输出格式】
对于每个 2 操作输出一行,四舍五入保留正好 3 位小数。
【样例输入】
5
5 3 4 2 1
5
2 1 4 3
1 4 8
2 3 5 3
1 2 2
2 1 3 2
【样例输出】
3.833
4.333
4.000
【样例说明】
第一个操作询问学号在 [1, 4] 之间的同学分成 3 个考场的平均分的平均分
的最大值,最优策略是:{1}, {2, 4}, {3},平均分是![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/88c0ce455191122fc76d8f8634961620.png#pic_center)

第二个操作把学号为 4 的同学的分数变为 8。
第三个操作询问学号在 [3, 5] 之间的同学分成 3 个考场的平均分的平均分
的最大值,最优策略是:{3}, {4}, {5}。
第四个操作把学号为 2 的同学分数变为 2。
第五个操作询问学号在 [1, 3] 之间的同学分成 2 个考场的平均分的平均分
的最大值,最优策略是:{1}, {2 3}。
【评测用例规模与约定】
对于全部评测用列,n ≤ 200000, q ≤ 200000, 任意时刻同学的分数 vi ≤ 10^9, k ≤ r - l+ 1。
评测时将使用 10 个评测用例测试你的程序,每个评测用例的限制如下:







  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

奥丁之眼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值