第十四届蓝桥杯 三十天刷题 第三天

📢📢📢哈喽哈喽 朋友们同学们,交作业时间到~


  1. 💥门牌制作💥

📄题目描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

小蓝要为一条街的住户制作门牌号。

这条街一共有 2020 位住户,门牌号从 1 到 2020 编号。

小蓝制作门牌的方法是先制作 0 到 9 这几个数字字符,最后根据需要将字符粘贴到门牌上,例如门牌 1017 需要依次粘贴字符 1、0、1、7,即需要 11 个字符 0,2 个字符 1,1 个字符7。

请问要制作所有的 1 到 2020 号门牌,总共需要多少个字符 2?

❓思路分享

这道题题意很好理解,这里提供两个思路:

🍋直接遍历1-2020,求1-2020中的每个数的数位,用一个变量来记录2出现的次数即可

🍌将1-2020作为字符串来处理,用charAt方法提出1-2020每个数的数位,如果是2 ,答案+1

📗参考代码1

public class Main {
    public static void main(String[] args) {
        int ans = 0;
        for(int i = 1; i<= 2020;i++){
            ans += check(i);
        }
        System.out.println(ans);
    }

    static int check(int i) {
        int cnt = 0;
        while (i != 0) {
            if (i % 10 == 2) cnt++;
            i  /= 10;
        }
        return cnt;
    }
}

📗参考代码2

public class Main  {
    public static void main(String[] args) {
        int cnt = 0;
        String s = "";
        for(int i = 1;i <= 2020; i++){
            s = i + "";
            for (int j = 0; j <s.length() ; j++) {
                if(s.charAt(j)=='2') cnt ++;
            }
        }
        System.out.println(cnt);
    }
}

  1. 🍒货物摆放🍒

📄题目描述

小蓝有一个超大的仓库,可以摆放很多货物。

现在,小蓝有 n 箱货物要摆放在仓库,每箱货物都是规则的正方体。小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、宽、高。

小蓝希望所有的货物最终摆成一个大的长方体。即在长、宽、高的方向上分别堆 LWH 的货物,满足 n=L×W×H

给定 n,请问有多少种堆放货物的方案满足要求。

例如,当 n=4 时,有以下 6 种方案:1×1×4、1×2×2、1×4×1、2×1×2、2×2×1、4×1×1

请问,当n=2021041820210418 (注意有 16 位数字)时,总共有多少种方案?

提示:建议使用计算机编程解决问题。

📌答案提交

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

❓思路分享

🔖n=L×W×H 即L 、W、H 均为 n 的因子 我们可以将n的因子用一个集合维护起来 ,然后用三层循环遍历这个集合,累加三数乘积为n的个数,最后循环结束便得到了最终的方案数!

🍒这里要注意定义long型的集合,因为n已经超过了int范围( -2147483648~2147483647)了,一定要注意了奥

📗参考代码

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

public class Main {
    public static void main(String[] args) {
        long n = 2021041820210418l;
        List<Long> list = new ArrayList<>();
        for (long i = 1; i <= n / i; i++) {
            if (n % i == 0) {
                list.add(i);//线性筛筛出来的因子(前一半)
                list.add(n / i);//后一半因子(这样提升了筛因子的效率)
            }
        }
        int ans = 0;
        //注意这种增强for循环遍历时 是直接取得list中的元素 而不是下标
        for (long i : list) {
            for (long j : list) {
                for (long k : list) {
                    if (i * j * k == n) ans++;
                }
            }
        }
        System.out.println(ans);
    }
}

  1. 🍐跳跃🍐

📄题目描述

小蓝在一个 nm 列的方格图中玩一个游戏。

开始时,小蓝站在方格图的左上角,即第 11 行第 11 列。

小蓝可以在方格图上走动,走动时,如果当前在第 r 行第 c 列,他不能走到行号比 r 小的行,也不能走到列号比 c 小的列。同时,他一步走的直线距离不超过 3。

例如,如果当前小蓝在第 3 行第 5 列,他下一步可以走到第 3 行第 6 列、第 3 行第 7 列、第 3 行第 8 列、第 4 行第 5 列、第 4 行第 6 列、第 4 行第 7 列、第 5 行第 5 列、第 5 行第 6 列、第 6 行第 5 列之一。

小蓝最终要走到第 n 行第 m 列。

在图中,有的位置有奖励,走上去即可获得,有的位置有惩罚,走上去就要接受惩罚。奖励和惩罚最终抽象成一个权值,奖励为正,惩罚为负。

小蓝希望,从第 1 行第 1 列走到第 n 行第 m 列后,总的权值和最大。请问最大是多少?

😭原谅我写太菜了,等我学完dp再来切跳跃叭


  1. 🍎重新排序🍎

📄问题描述

给定一个数组 A 和一些查询 Li,Ri, 求数组中第 Li 至第 Ri 个元素之和。

小蓝觉得这个问题很无聊, 于是他想重新排列一下数组, 使得最终每个查 询结果的和尽可能地大。小蓝想知道相比原数组, 所有查询结果的总和最多可 以增加多少?

🔑输入格式

输入第一行包含一个整数 n

第二行包含 n 个整数 1,2,⋯,A1,A2,⋯,An, 相邻两个整数之间用一个空格分隔。

第三行包含一个整数 m 表示查询的数目。

接下来 m 行, 每行包含两个整数LiRi, 相邻两个整数之间用一个空格分 隔。

🔒输出格式

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

❓思路分享

📕这道题做难理解的在于通过差分来统计区间被查询的次数,不了解差分的同学可以先去学一下差分,再做一道模板题小明的彩灯,然后再来消化这道题会对它有更好的理解。

🔖我们贪心的考虑,要想重新排序后查询的总和最大,那我们是不是可以让查询最多次的下标放最大数字,即重新排序后的数组应满足:尽可能让越大的数字保存在被查询次数越多的下标!

明白了大体的思想,那我们如何来跟据给定的查询区间知道最终哪些区间被查询的次数呢?

🍎这里就需要用到前缀和差分思想。我们用一个数组g作为差分数组,在得到每个查询[ l , r ]时,差分思想体现在我们让g[ l - 1]--,g[r] ++(题目给的区间的下标从1开始)并将差分数组变成前缀和数组,我们就会神奇的发现如果某个区间[l,r]被查询了一次,那么我们通过了以上“--”“++”的操作,在当前(已经求前缀和)数组g当中区间[l,r]的值都被+1!这样我们的g数组便达到了记录下标查询次数的作用啦。

举个栗子🍐

假设某次查询区间是:l = 2 , r = 5 ,g[2] ++, g[5]-- , g数组如下:

g[0]

g[1]

g[2]

g[3]

g[4]

g[5]

0

0

1

0

0

-1

然后我们将它处理成前缀和数组,就变成了:

g[0]

g[1]

g[2]

g[3]

g[4]

g[5]

0

0

1

1

1

0

是不是很神奇!👏👏👏是不是这段区间的值都+1了,这样到循环结束,我们就维护好了一个区间被查询次数的数组啦~😋

到现在我们只需要将原数组a与最终的g数组排序,这样两个数组较大值对应着较大值,就满足了我们刚开始说的重新排序后的数组应满足:尽可能让越大的数字保存在被查询次数越多的下标!

最后只需要按照题意计算新旧数组查询区间和的差就行啦~

📗参考代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Arrays;

public class Main {
    static int N = 100010;
    static int[] a = new int[N];
    //前缀和数组
    static long[] s = new long[N];
    //差分数组
    static long[] g = new long[N];
    static int n;
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
    
    public static void main(String[] args) throws IOException {
        n = Integer.parseInt(br.readLine());
        String[] v = br.readLine().split(" ");
        for(int i = 1; i <= n; i++) {
            a[i] =Integer.parseInt(v[i-1]);
            s[i] = s[i-1] + a[i];//初始化前缀和数组
        }
        int m = Integer.parseInt(br.readLine());
        long res = 0;//记录重新排序前的某段区间的和
        for(int i = 0; i < m;i++) {
            v = br.readLine().split(" ");
            int l = Integer.parseInt(v[0]);
            int r = Integer.parseInt(v[1]);
            g[l-1]++;
            g[r]--;
            res += s[r] - s[l-1];//累加原数组被查询的和
        }
        for(int i = 1; i <= n; i++) {
            g[i] += g[i-1];
        }
        long ans = 0;
        Arrays.sort(a);
        Arrays.sort(g);
        int pre = g.length - 1;
        while(g[pre]!=0) {
            ans += g[pre] *a[pre];//g数组保存的是查询次数,所以这乘起来
            pre --;
        }
        System.out.println(ans - res);
    }
}

好啦~今天费尽周折还没能写完所有题解,实在是太菜啦😭感觉这几天做题写博客效率好低啊,每天都最后一小时才打卡,得及时调整了,时间不多啦😳

📢📢📢好了,各位同学,明天见咯 大家拜拜~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值