蓝桥杯31天真题冲刺|题解报告|第四天

大家好,我是snippet,今天是刷蓝桥真题的第四天,今天的知识点包含 全排列+二分+前缀和,下面是我今天的题解

目录

一、9数算式

二、山

三、最少刷题数

四、完全平方数 


一、9数算式

题目链接:9数算式 - 蓝桥云课 (lanqiao.cn)

题目要求:

题目描述

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

观察如下的算式:

9213×85674=789314562

左边的乘数和被乘数正好用到了 1 ~ 9 的所有数字,每个 1 次。 而乘积恰好也是用到了 1 ~ 9 的所有数字,并且每个 1 次。

请你借助计算机的强大计算能力,找出满足如上要求的 9 数算式一共有多少个?

注意:

  1. 总数目包含题目给出的那个示例。
  2. 乘数和被乘数交换后作为同一方案来看待。

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 128M

解题思路:

因为是求a*b == n的方案数(a,b一起包含数字1-9,n也包含数字1-9),那我们就可以枚举1-9九个数字所有可能(全排列),然后再对每一种可能进行数据分割再进行乘积,最后再对乘积的结果进行判断是否包含1-9的所有数字

代码:

package 蓝桥杯31天真题冲刺.Day4;

import java.io.*;

/**
 * @author snippet
 * @data 2023-03-07
 * 9数算式-蓝桥云课
 */
// 全排列
public class T1_9数算式 {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
    static StreamTokenizer st = new StreamTokenizer(br);

    static int n = 9;
    static int ans = 0;
    static int[] nums = {1,2,3,4,5,6,7,8,9};

    public static void main(String[] args) throws IOException {
        dfs(0,8);
        pw.println(ans);
        pw.flush();
        br.close();
    }

    // 对1-9进行全排列
    // left为头指针 right为尾指针 当left==right的时候退出
    static void dfs(int left, int right) {
        // 递归出口
        if (left == right) {
//            for (int i = 0; i < 8; i++) {
//                pw.print(nums[i] + " ");
//            }
//            pw.println();
            count();
        } else {
            for (int i = left; i <= right; i++) {
                swap(left, i);
                // 递归
                dfs(left+1, right);
                // 数据回溯
                swap(left, i);
            }
        }
    }

    static void swap(int a, int b) {
        int temp = nums[a];
        nums[a] = nums[b];
        nums[b] = temp;
    }

    // 对1-9排序后的每种情况进行乘数 和 被乘数的划分
    static void count() {
        int a;
        int b;
        StringBuilder s = new StringBuilder("");

        for (int i = 0; i < n; i++) {
            s.append(nums[i]);
        }

//        String str = s.toString();
        int l = 1;
        while (l <= n/2) {
            a = Integer.parseInt(s.substring(0,l));
//            pw.println(a);
            b = Integer.parseInt(s.substring(l,n));
            int temp = a*b;
            if (isTrue(temp)) {
                ans++;
            }
            l++;
        }
    }

    // 判断 a * b 的乘积是不是包含1-9每个数字
    static boolean isTrue(int x) {
        int[] cnt = new int[10];
        while (x != 0) {
            cnt[x % 10]++;
            x /= 10;
        }
        for (int i = 1; i <= 9; i++) {
            if (cnt[i] > 1 || cnt[i] == 0) return false;
        }
        return true;
    }
}

二、山

题目链接:山 - 蓝桥云课 (lanqiao.cn)

题目要求:

问题描述

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

这天小明正在学数数。

他突然发现有些止整数的形状像一挫 “山”, 比如 123565321、145541, 它们左右对称 (回文) 且数位上的数字先单调不减, 后单调不增。

小朋数了衣久也没有数完, 他惒让你告诉他在区间 [2022,2022222022] 中有 多少个数的形状像一座 “山”。

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 512M

解题思路:

直接对区间[2022,2022222022]里面的数据依次进行判断,是否满足左右对称 (回文) 且数位上的数字先单调不减, 后单调不增,进行结果计数即可

代码:

package 蓝桥杯31天真题冲刺.Day4;

import java.io.*;

/**
 * @author snippet
 * @data 2023-03-07
 * 山-蓝桥云课
 */
public class T2_山 {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
    static StreamTokenizer st = new StreamTokenizer(br);

    static int ans = 0;

    static boolean isTure(int x) {
        String s = Integer.toString(x);
        int left = 0;
        int right = s.length()-1;
        while (left <= right) {
            if (left == 0 && right == s.length()-1) {
                if (s.charAt(left) == s.charAt(right)) {
                    left++;
                    right--;
                } else {
                    return false;
                }
            } else {
                if (s.charAt(left) == s.charAt(right) && s.charAt(left) >= s.charAt(left-1) &&
                s.charAt(right) >= s.charAt(right+1)) {
                    left++;
                    right--;
                } else {
                    return false;
                }
            }
        }
        return true;
    }

    public static void main(String[] args) throws IOException {
        for (int i = 2022; i <= 2022222022; i++) {
            if (isTure(i)) ans++;
        }
        // 3138
        pw.println(ans);
        pw.flush();
        br.close();
    }
}

三、最少刷题数

题目链接:最少刷题数 - 蓝桥云课 (lanqiao.cn)

题目要求:

问题描述

小蓝老师教的编程课有 N 名学生, 编号依次是 1…N 。第 i 号学生这学期刷题的数量是 Ai​ 。

对于每一名学生, 请你计算他至少还要再刷多少道题, 才能使得全班刷题比他多的学生数不超过刷题比他少的学生数。

输入格式

第一行包含一个正整数 N 。

第二行包含 N 个整数: A1​,A2​,A3​,…,AN​.

输出格式

输出 N 个整数, 依次表示第 1…N 号学生分别至少还要再刷多少道题。

解题思路:

根据梗佬的题解写的分析(此题解来自于梗佬的题解:最少刷题数-执梗):

这个题可以使用二分+前缀和一起求解,我们先用一个数组arr存学生的刷题数,然后再用一个数组count来记录刷题数的个数,这样我们就可以使用二分答案来对刷题数进行求解。找到符合条件的刷题数 x 即可。

二分判断时如果当前同学不需要额外刷题即符合要求,我们输出0即可。在二分判断时,当它的刷题数变为 x 时,比他刷题多的同学数量就应该是cnt[100000]-cnt[x],比他刷题少的同学数量为cnt[x-1]-1。

为什么还需要减去1呢?因为这位同学原先的刷题数是小于x的, 此时他已经变为x了,所以统计比他少刷题数的同学时需要把他去掉。这样二分得到的答案是他的目标刷题量,减去他本身的刷题量即是答案。

代码:

package 蓝桥杯31天真题冲刺.Day4;

import java.io.*;

/**
 * @author snippet
 * @data 2023-03-07
 * 最少刷题数-蓝桥云课
 */
// 前缀和 + 二分
public class T3_最少刷题数 {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
    static StreamTokenizer st = new StreamTokenizer(br);

    static int n;// n表示学生个数
    static int[] arr = new int[100100];// 一维数组arr存学生刷题数
    static int[] count = new int[100100];// 一维数组count用来存i位置及之前所有位置的刷题数之和(i表示刷题数)

    public static void main(String[] args) throws IOException {
        String[] s = br.readLine().split(" ");
        n = Integer.parseInt(s[0]);

        s = br.readLine().split(" ");
        for (int i = 1; i <= n; i++) {
            arr[i] =  Integer.parseInt(s[i-1]);
            count[arr[i]]++;
        }

        // 求刷题数的前缀和
        for (int i = 1; i <= 100000; i++) {
            count[i] += count[i-1];
        }

        for (int i = 1; i <= n; i++) {
            // 当比这个同学的刷题数多的刷题数的数量 小于等于 比这个同学的刷题数少的刷题数的数量 直接输出0
            if (count[100000] - count[arr[i]] <= count[Math.max(0, arr[i]-1)]) {
                pw.print(0 + " ");
                continue;
            }

            // 二分求满足条件的刷题数
            int left = arr[i]+1;
            int right = 100000;
            while (left < right) {
                int mid = left + right >> 1;
                // 因为本来该同学的刷题数是 在mid的左边 因为它已经移到mid
                if (count[100000] - count[mid] > count[mid-1] - 1) {
                    left = mid+1;
                } else {
                    right = mid;
                }
            }
            pw.print((left - arr[i]) + " ");
        }
        pw.flush();
        br.close();
    }
}

四、完全平方数 

题目链接:完全平方数 - 蓝桥云课 (lanqiao.cn)

题目要求:

问题描述

一个整数 a 是一个完全平方数, 是指它是某一个整数的平方, 即存在一个整数 b, 使得 a=b2 。

给定一个正整数 n, 请找到最小的正整数 x, 使得它们的乘积是一个完全平方数。

输入格式

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

输出格式

输出找到的最小的正整数 x 。

样例输入 1

12

样例输出 1

3

样例输入 2

15

样例输出 2

15

评测用例规模与约定

对于 30% 的评测用例, 11≤n≤1000, 答案不超过 1000 。

对于 60% 的评测用例, 1≤n≤10^8, 答案不超过 10^8 。

对于所有评测用例, 1≤n≤10^12, 答案不超过 10^12 。

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

解题思路:

因为是求满足完全平方数的乘积,如果给定的数字n,它的质因数里面含有完全平方数x,那(n/x * n) 就是一个完全平方数,那么我们要求的结果就是n/x

代码:

package 蓝桥杯30天真题冲刺.Day4;

import java.io.*;

/**
 * @author snippet
 * @data 2023-03-07
 * 完全平方数-蓝桥云课
 */
// 完全平方数的质因数都是偶数次出现的
public class T4_完全平方数 {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
    static StreamTokenizer st = new StreamTokenizer(br);

    public static void main(String[] args) throws IOException {
        st.nextToken();
        long n = (long) st.nval;
        long ans = n;
        // 因为完全平方数的质因数都是偶数次出现的
        // 那我们找到 n 的最小质因数 这个数同时也得是完全平方数
        // 则 n * ans 就是一个完全平方数
        for (long i = 2; i * i <= n; i++) {
            while (ans % (i * i) == 0) {
                ans = ans / (i * i);
            }
        }
        pw.println(ans);
        pw.flush();
        br.close();
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值