大家好,我是snippet,今天是刷蓝桥真题的第四天,今天的知识点包含 全排列+二分+前缀和,下面是我今天的题解
目录
一、9数算式
题目要求:
题目描述
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
观察如下的算式:
9213×85674=789314562
左边的乘数和被乘数正好用到了 1 ~ 9 的所有数字,每个 1 次。 而乘积恰好也是用到了 1 ~ 9 的所有数字,并且每个 1 次。
请你借助计算机的强大计算能力,找出满足如上要求的 9 数算式一共有多少个?
注意:
- 总数目包含题目给出的那个示例。
- 乘数和被乘数交换后作为同一方案来看待。
运行限制
- 最大运行时间: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;
}
}
二、山
题目要求:
问题描述
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
这天小明正在学数数。
他突然发现有些止整数的形状像一挫 “山”, 比如 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();
}
}