第十届蓝桥杯 2019年国赛真题 (Java 大学B组)

挂挂挂,先挂


#A 递增序列

本题总分:5 分


问题描述

对于一个字母矩阵,我们称矩阵中的一个递增序列是指在矩阵中找到两个字母,它们在同一行,同一列,或者在同一 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

答案提交

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


52800

calcCode:

import java.io.*;

public class Test {

    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream("inc.txt")));
        char[][] map = new char[30][];
        for (int i = 0; i < 30; i++)
            map[i] = in.readLine().toCharArray();
        int cnt = 0;
        int[] offsetN = { 0, 0, -1, 1, -1, -1, 1, 1 };
        int[] offsetM = { -1, 1, 0, 0, -1, 1, 1, -1 };
        for (int k = 0; k < 30; k++) {
            for (int g = 0; g < 50; g++) {
                char start = map[k][g];
                for (int z = 0; z < 8; z++) {
                    for (int i = k + offsetN[z], j = g + offsetM[z]; i >= 0 && i < 30 && j >= 0 && j < 50; i += offsetN[z], j += offsetM[z])
                        if (map[i][j] > start && (k < i || g < j)) cnt++;
                }
            }
        }
        System.out.println(cnt);
    }
}

#B 平方拆分

本题总分:5 分


问题描述

将 2019 拆分为若干个两两不同的完全平方数之和,一共有多少种不同的方法?
注意交换顺序视为同一种方法,例如 132 + 252 + 352 = 2019 与 132 + 352 +252 = 2019 视为同一种方法。


答案提交

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


52574

calcCode:

public class Test {
	
	static int cnt;
	
    public static void main(String[] args) {
    	dfs(2019, -1);
    	System.out.println(cnt);
    }
    
    static void dfs(int num, int start) {
    	if (num < 0) return;
    	if (num == 0) cnt++;
    	else 
    		for (int i = start + 1, high = (int)Math.sqrt(num); i <= high; i++)
    			dfs(num - i * i, i);
    }
}

如果保证拆分出的元素是递增的,那么拆分的方法是不会重复的
如果保证拆分出的元素是严格递增的,那么拆分的元素和方法都是不会重复的

这个道理在绝大多数情况下都适用


#C 切割

本题总分:10 分


问题描述

在 4 × 4 的方格矩阵中画一条直线。则直线穿过的方格集合有多少种不同的可能?这个里直线穿过一个方格当且仅当直线将该方格分割成面积都大于 0 的两部分。


答案提交

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


不会


#D 最优旅行

本题总分:10 分


问题描述

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


答案提交

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


40173

calcCode:

import java.io.IOException;
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {

    static int V, beijing;
    static boolean[] visit;
    static List<Edge>[] graph;
    static int endDay = 0x3F3F3F3F;
    static String endTime = "23:59";
    static Map<String, Integer> table;

    public static void main(String[] args) throws IOException {
        ByteArrayInputStream data = null;
        {
            InputStream resource = new FileInputStream("trip.txt");
            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
            byte[] buff = new byte[8192];
            int len = 0;
            while ((len = resource.read(buff)) != -1)
                byteOut.write(buff, 0, len);
            data = new ByteArrayInputStream(byteOut.toByteArray());
        }
        BufferedReader in = new BufferedReader(new InputStreamReader(data, "gbk"));
        Pattern pattern = Pattern.compile("([\u4e00-\u9fa5]+)");
        table = new HashMap();
        String line = null;
        in.readLine();
        while ((line = in.readLine()) != null) {
            Matcher matcher = pattern.matcher(line);
            while (matcher.find()) {
                String city = matcher.group();
                if (table.get(city) == null)
                    table.put(city, V++);
            }
        }
        data.reset();
        in.close();
        in = new BufferedReader(new InputStreamReader(data, "gbk"));
        line = in.readLine();

        graph = new List[V];
        visit = new boolean[V];
        for (int i = 0; i < V; i++)
            graph[i] = new ArrayList();
        while ((line = in.readLine()) != null) {
            StringTokenizer tok = new StringTokenizer(line);
            Edge edge = new Edge(tok.nextToken(),
                                    tok.nextToken(),
                                    table.get(tok.nextToken()),
                                    tok.nextToken(),
                                    tok.nextToken());
            graph[edge.v].add(edge);
        }
        beijing = table.get("北京");
        visit[beijing] = true;
        dfs(beijing, 0, "12:00", 1, new ArrayDeque());
        System.out.println(V);
        System.out.println((endDay + V - 1) + "天 "+ endTime);
    }

    static void dfs(int city, int day, String time, int vcnt, Deque<String> deque) {
        if (day > endDay) return;
        if (vcnt == V) {
            for (Edge edge: graph[city]) {
                if (edge.e == beijing) {
                    int nowDay = day;
                    String nowTime = edge.end;
                    if (nowTime.compareTo(time) > 0) nowDay++;
                    if (nowDay < endDay || nowTime.compareTo(endTime) < 0) {
                        for (String c: deque)
                            System.out.print(c + "<-");
                        System.out.println();
                        endDay = nowDay;
                        endTime = nowTime;
                    }
                }
            }
        } else {
            for (Edge edge: graph[city]) {
                if (visit[edge.e]) continue;
                visit[edge.e] = true;
                deque.push(edge.city);
                dfs(edge.e, day + (time.compareTo(edge.start) > 0? 1: 0), edge.end, vcnt + 1, deque);
                deque.pop();
                visit[edge.e] = false;
            }
        }
    }

    static class Edge {

        int v, e;

        String city, train, start, end;

        Edge(String train, String city, int e, String start, String end) {
            this.v = table.get(city);
            this.city = city;
            this.e = e;
            this.start = start;
            this.end = end;
        }
    }
}

再把搜索的结果转换一下

public class Test {
	
	public static void main(String[] args) throws IOException {
		// 28天 09:33
		System.out.println((28 * 24 + 9) * 60 + 33 - 12 * 60);
		System.out.println(1440 * 28 + 9 * 60 + 33 - 12 * 60);
	}
}

十月 O I 一场空,一道真题见祖宗


#E 序列求和

本题总分:15 分


问题描述

学习了约数后,小明对于约数很好奇,他发现,给定一个正整数 t,总是可以找到含有 t 个约数的整数。小明对于含有 t 个约数的最小数非常感兴趣,并把它定义为 St 。
例如 S1 = 1, S2 = 2, S3 = 4, S4 = 6,· · · 。
现在小明想知道,前 60 个 Si 的和是多少?即 S1 + S2 + · · · + S60 是多少?


答案提交

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


101449 || 292809912969717649

calcCode:

public class Test {

    public static void main(String[] args) {
        int res = 0;
        int[] cnt = new int[62];
        for (int i = 1; true; i++) {
            int tmp = factors(i);
            if (tmp >= 60) {
                cnt[60] = cnt[61] = i;
                break;
            }
            if (cnt[tmp] == 0) cnt[tmp] = i;
        }
        for (int i = 60; i > 0; i--) {
            if (cnt[i] == 0 || cnt[i] > cnt[i + 1]) cnt[i] = cnt[i + 1];
            res += cnt[i];
        }
        System.out.print(res);
    }

    static int factors(long n) {
    	int res = 1, now;
    	for (int i = 2; i * i <= n; i++) {
    		now = 0;
    		while (n % i == 0) {
    			now++;
    			n /= i;
    		}
    		if (now > 0) {
    			res *= now + 1;
    		}
    	}
    	return n <= 1? res: (res << 1);
    }
}

网上的另一种结果的解法

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

public class Test {

    static final int[] prime = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541 };

    public static void main(String[] args) {
        Map<Integer, Double> map = new HashMap();
        long res = 0;
        map.put(1, 1.0);
        for (int i = 2; i <= 60; i++)
            resolve(i, 2, 0, i, map, new int[1024]);
        for (int i = 1; i <= 60; i++)
            res += map.get(i);
        System.out.println(res);
    }

    static void resolve(int n, int start, int cur, int val, Map map, int[] buff) {
        if (val == 1) calc(n, cur, map, buff);
        else while (start <= val) {
            if (val % start == 0) {
                buff[cur] = start;
                resolve(n, start, cur + 1, val / start, map, buff);
            }
            start++;
        }
    }

    static void calc(int n, int cur, Map<Integer, Double> map, int[] buff) {
        double total = 1;
        int i = 0;
        while (cur-- > 0)
            total *= Math.pow(prime[i++], buff[cur] - 1);
        if (map.get(n) == null || map.get(n) > total)
            map.put(n, total);
    }
}

#F 最长子序列

时间限制: 1.0s 内存限制: 512.0MB 本题总分:15 分


问题描述

我们称一个字符串 S 包含字符串 T 是指 T 是 S 的一个子序列,即可以从字符串 S 中抽出若干个字符,它们按原来的顺序组合成一个新的字符串与 T 完全一样。
给定两个字符串 S 和 T,请问 T 中从第一个字符开始最长连续多少个字符被 S 包含?


输入格式

输入两行,每行一个字符串。第一行的字符串为 S,第二行的字符串为 T。
两个字符串均非空而且只包含大写英文字母。


输出格式

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


测试样例1

Input:
ABCDEABCD
AABZ

Output:
3

评测用例规模与约定

对于 20% 的评测用例,1 ≤ |T| ≤ |S | ≤ 20;
对于 40% 的评测用例,1 ≤ |T| ≤ |S | ≤ 100;
对于所有评测用例,1 ≤ |T| ≤ |S | ≤ 1000。


code:

import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String S = in.readLine();
        String T = in.readLine();
        int j = 0;
        for (int i = 0, ih = S.length(), jh = T.length(); i < ih && j < jh; i++)
            if (S.charAt(i) == T.charAt(j)) j++;
        System.out.println(j);
    }
}

经典第一题友好


#G 数正方形

时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分


问题描述

在一个 N × N 的点阵上,取其中 4 个点恰好组成一个正方形的 4 个顶点,一共有多少种不同的取法?
由于结果可能非常大,你只需要输出模 109 + 7 的余数。
在这里插入图片描述
如上图所示的正方形都是合法的。


输入格式

输入包含一个整数 N。


输出格式

输出一个整数代表答案。


测试样例1

Input:
4

Output:
20

评测用例规模与约定

对于所有评测用例,2 ≤ N ≤ 1000000。


在这里插入图片描述在这里插入图片描述
规律显然易见

code:

import java.io.IOException;
import java.io.InputStream;

public class Main {

    static final int mod = 1000000007;

    public static void main(String[] args) throws IOException {
        long n = nextInt(System.in);
        long res = ((n - 1)* (n - 1)) % mod;
        for (int i = 2; i < n; i++)
            res = (res + (((n - i) * (n - i)) % mod) * i) % mod;
        System.out.println(res);
    }

    static int nextInt(InputStream in) throws IOException {
        int n = 0, c = in.read();
        while (c < '0' || c > '9') c = in.read();
        while (c >='0' && c <='9') {
            n = n * 10 + (c & 0xf);
            c = in.read();
        }
        return n;
    }
}

#H 大胖子走迷宫

时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分


问题描述

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


输入格式

输入的第一行包含两个整数 n, k。
接下来 n 行,每行一个由 n 个字符组成的字符串,字符为 + 表示为空地,
字符为 * 表示为阻碍物。


输出格式

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


测试样例1

Input:
9 5
+++++++++
+++++++++
+++++++++
+++++++++
+++++++++
***+*****
+++++++++
+++++++++
+++++++++

Output:
16

评测用例规模与约定

对于 30% 的评测用例,1 ≤ n ≤ 50。
对于 60% 的评测用例,1 ≤ n ≤ 100。
对于所有评测用例,1 ≤ n ≤ 300,1 ≤ k ≤ 1000。


code:

import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.Queue;

public class Test {

    public static void main(String[] args) {
        InputReader in = new InputReader(System.in);
        int n = in.nextInt(), k = in.nextInt();
        if (n <= 5) System.out.print('0');
        else {
            int map[][] = new int[n][n], INF = 0x3F3F3F3F;
            boolean[][] visit = new boolean[n][n];
            for (int i = 0, hi = n - 1; i <= hi; i++) {
                if (i < hi)
                    map[1][i] = map[hi - 1][i] = map[i][1] = map[i][hi - 1] = 1;
                map[0][i] = map[hi][i] = map[i][0] = map[i][hi] = 2;
            }
            int[] os2i = { -1, -1, 0, 1, 1, 1, 0, -1 };
            int[] os2j = { 0, 1, 1, 1, 0, -1, -1, -1 };
            int[] os1i = { -2, -2, -2, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2 };
            int[] os1j = { 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2, -2, -2, -2, -1 };
            for (int i = 0, x, y; i < n; i++)
                for (int j = 0; j < n; j++) {
                    if (in.split() == '*') {
                        map[i][j] = INF;
                        for (int l = 0; l < 8; l++) {
                            x = i + os2i[l];
                            y = j + os2j[l];
                            if (x < 0 || x >= n || y < 0 || y >= n || map[x][y] > 2) continue;
                            map[x][y] = 2;
                        }
                        for (int l = 0; l < 16; l++) {
                            x = i + os1i[l];
                            y = j + os1j[l];
                            if (x < 0 || x >= n || y < 0 || y >= n || map[x][y] > 1) continue;
                            map[x][y] = 1;
                        }
                    }
                }
            class Step {

                int x, y, time;

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

                Step relax() {
                    this.time++;
                    return this;
                }
            }
            Queue<Step> queue = new LinkedList();
            int[] offsetX = { -1, 0, 1, 0 };
            int[] offsetY = { 0, 1, 0, -1 };
            int endX = n - 3, endY = n - 3;
            queue.offer(new Step(2, 2, 0));
            while (queue.size() > 0) {
                Step now = queue.poll();
                if (now.x == endX && now.y == endY) {
                    System.out.print(now.time);
                    break;
                }
                for (int i = 0, x, y, s; i < 4; i++) {
                    x = now.x + offsetX[i];
                    y = now.y + offsetY[i];
                    s = now.time / k;
                    if (x < 0 || x >= n || y < 0 || y >= n || visit[x][y] || map[x][y] > s) continue;
                    visit[x][y] = true;
                    queue.offer(new Step(x, y, now.time + 1));
                }
                queue.offer(now.relax());
            }
        }
    }

    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;
        }
    }
}

广搜单源最短路

题目不难,优化麻烦
这里地图数字的意思是在 map[i][j] * k 的时间可以达到此地

其实可以把边界也看做是障碍物,这样用 O(n) 的空间就可以换取每一步减少 4个越界判断,但想到的时候已经快写完了,就算了,不会对其性质造成影响


#I 估计人数

时间限制: 1.0s 内存限制: 512.0MB 本题总分:25 分


问题描述

给定一个 N × M 的方格矩阵,矩阵中每个方格标记 0 或者 1 代表这个方格是不是有人踩过。
已知一个人可能从任意方格开始,之后每一步只能向右或者向下走一格。
走了若干步之后,这个人可以离开矩阵。这个人经过的方格都会被标记为 1,包括开始和结束的方格。注意开始和结束的方格不需要一定在矩阵边缘。
请你计算至少有多少人在矩阵上走过。


输入格式

输入第一行包含两个整数 N、M。
以下 N 行每行包含 M 个整数 (0/1),代表方格矩阵。


输出格式

输出一个整数代表答案。


测试样例1

Input:
5 5
00100
11111
00100
11111
00100

Output:
3

评测用例规模与约定

对于所有评测用例,1 ≤ N, M ≤ 20,标记为 1 的方格不超过 200 个。


code:

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 分考场

时间限制: 10.0s 内存限制: 512.0MB 本题总分:25 分


问题描述

古语有云:春风得意马蹄疾,一日看尽长安花。
当然在一场考试中所有人都春风得意马蹄疾是不可能的,尤其是碰到一些毒瘤出题人的时候。


又到了每月一次的月考,又是 xf 老师出题。
上一次 xf 老师出的题太毒瘤了,平均分只有 40 40 40 多,同学们都非常不满意,毕竟别的科的平均分都是 80 80 80 多。
这次 xf 为了不被同学们寄刀片,想了一个办法:只公布所有考场的平均分的平均分。这样他就可以通过调整考场的分配方式,使得平均分显得高。(每个考场都可以容纳无限人)
每次考试也不是所有同学都参加的,只有学号在 [ l , r ] [l,r] [l,r] 这个区间中的同学会参加。
他想知道对于每次考试,他调整过考场后,所有考场的平均分的平均分的最大值。
当然,同学们也可能会努力学习或整日颓废使成绩发生改变。


输入格式

输入的第一行包含一个整数 n n n
第二行包含 n n n 个整数,第 i i i 个数 v i v_{i} vi,表示开始时每个同学的成绩。
第三行包含一个整数 q q q,表示有 q q q 次操作。
之后 q q q 行,每行描述一个操作,第一个数表示操作类型。
如果操作为 1 p x 1 p x 1px,表示学号为 p p p 的同学分数变为 x x x
如果操作为 2 l r k 2 l r k 2lrk, 表示把学号在 [ l , r ] [l,r] [l,r] 中的同学分成 k k k 个考场,求这 k k k 个考场的平均分的平均分的最大值。


输出格式

对于每个 2 操作输出一行,四舍五入保留正好 3 位小数。


测试样例1

Input:
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

Output:
3.833
4.333
4.000

Explanation:
第一个操作询问学号在 [1, 4] 之间的同学分成 3 个考场的平均分的平均分的最大值,最优策略是:{1}, {2, 4}, {3},平均分是 ${formula_1}
第二个操作把学号为 4 的同学的分数变为 8。
第三个操作询问学号在 [3, 5] 之间的同学分成 3 个考场的平均分的平均分的最大值,最优策略是:{3}, {4}, {5}。
第四个操作把学号为 2 的同学分数变为 2。
第五个操作询问学号在 [1, 3] 之间的同学分成 2 个考场的平均分的平均分的最大值,最优策略是:{1}, {2 3}。

formula_1: 5 1 + 3 + 2 2 + 4 1 3 {{{5} \over {1}} + {{3 + 2} \over {2}} + {{4} \over {1}} } \over {3} 315+23+2+14


评测用例规模与约定

对于全部评测用列, n ≤ 200000 n ≤ 200000 n200000, q ≤ 200000 q ≤ 200000 q200000, 任意时刻同学的分数 v i ≤ 1 0 9 v_{i} ≤ 10^{9} vi109 k ≤ r − l + 1 k ≤ r − l + 1 krl+1

评测时将使用 10 10 10 个评测用例测试你的程序,每个评测用例的限制如下:
在这里插入图片描述


code:



  • 13
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 15
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值