大家好,我是snippet,今天是刷蓝桥真题的第十四天,今天的题包含 set 和 动态规划的知识,第四题的动态规划得先找规律找到它的状态转移式,下面是我今天的题解
一、组队
题目内容:
题目描述
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
作为篮球队教练,你需要从以下名单中选出 1 号位至 5 号位各一名球员,组成球队的首发阵容。
每位球员担任 1 号位至 5 号位时的评分如下表所示。请你计算首发阵容 1 号位至 5 号位的评分之和最大可能是多少?
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
解题思路:
直接肉眼暴力解决
代码:
package 蓝桥杯31天真题冲刺.Day14;
/**
* @author snippet
* @data 2023-03-07
* 组队-蓝桥云课
*/
public class T1_组队 {
public static void main(String[] args) {
System.out.println(97 + 99 + 99 + 97 + 98);
}
}
二、不同子串
题目内容:
题目描述
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
一个字符串的非空子串是指字符串中长度至少为 1 的连续的一段字符组成的串。例如,字符串 aaab 有非空子串 a, b, aa, ab, aaa, aab, aaab,一共 7 个。注意在计算时,只算本质不同的串的个数。
请问,字符串 0100110001010001 有多少个不同的非空子串?
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
解题思路:
这个题是找不同的字符串子串的个数,我们可以用set来存子串,答案就是set的长度
代码:
package 蓝桥杯31天真题冲刺.Day14;
import java.util.HashSet;
import java.util.Set;
/**
* @author snippet
* @data 2023-03-17
* 不同子串-蓝桥云课
*/
public class T2_不同子串 {
public static void main(String[] args) {
String s = "0100110001010001";
Set<String> set = new HashSet<>();
for (int i = 0; i < s.length(); i++) {
for (int j = i; j < s.length(); j++) {
set.add(s.substring(i, j+1));
}
}
// for(String t:set) {
// System.out.println(t);
// }
System.out.println(set.size());
}
}
三、等差数列
题目内容:
题目描述
数学老师给小明出了一道等差数列求和的题目。但是粗心的小明忘记了一 部分的数列,只记得其中 N 个整数。
现在给出这 N 个整数,小明想知道包含这 N 个整数的最短的等差数列有几项?
输入描述
输入的第一行包含一个整数 N。
第二行包含 N 个整数 A1,A2,⋅⋅⋅,AN。(注意 A1 ∼ AN 并不一定是按等差数列中的顺序给出)
其中,2≤N≤10^5,0≤Ai≤10^9。
输出描述
输出一个整数表示答案。
输入输出样例
示例
输入
5
2 6 4 10 20
输出
10
样例说明: 包含 2、6、4、10、20 的最短的等差数列是 2、4、6、8、10、12、14、16、 18、20。
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
解题思路:
给等差数列的部分数据,让我们求该等差数列的最短长度,因为求等差数列的最短长度,那我们先将给定的数据排序,最小则为第一项,最大则为最后一项,然后我们只需要求这个等差数列给定数据的最小公差,可以直接求最小差值,也可以用gcd求差值里面所有数的最大公约数也就是这个字符串可以构成最短等差数列的最小公差,如果公差为0则直接输出n,如果不为0,则用a[n] = a[1] + (n-1)*d ==> n = (a[n] - a[1]) / d + 1求等差数列的长度
代码:
package 蓝桥杯31天真题冲刺.Day14;
import java.io.*;
import java.util.Arrays;
/**
* @author snippet
* @data 2023-03-17
* 等差数列-蓝桥云课
*/
// gcd
public class T3_等差数列 {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
static int n,ans,g;// n表示数据的个数 ans表示这个等差数列的最小个数 g表示这个等差数列的公差
static int N = 100100;
static int[] a = new int[N];// 一维数组a存等差数列的部分数据
// 求最大公约数
static int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a%b);
}
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++) {
a[i] = Integer.parseInt(s[i-1]);
}
// 先对原始数据进行排序
Arrays.sort(a, 1, n+1);
// 所有连续数的差值的最大公约数也就是这个等差数列的公差了
g = a[2]-a[1];
for (int i = 2; i <= n; i++) {
g = gcd(g, a[i]-a[i-1]);
}
// 当公差为0时,这个等差数列就是常数数列
if (g == 0) ans = n;
else {
// an = a1 + (n-1)*d
ans = (a[n]-a[1]) / g + 1;
}
pw.println(ans);
pw.flush();
br.close();
}
}
四、波动数列
题目内容:
题目描述
观察这个数列:
1 3 0 2 −1 1 −2 ⋯
这个数列中后一项总是比前一项增加 2 或者减少 3。
栋栋对这种数列很好奇,他想知道长度为 n 和为 s 而且后一项总是比前一项增加 a 或者减少 b 的整数数列可能有多少种呢?
输入描述
输入的第一行包含四个整数 n,s,a,b,含义如前面说述。
其中,1≤n≤1000,−10^9≤s≤10^9,1≤a,b≤10^6。
输出描述
输出一行,包含一个整数,表示满足条件的方案数。由于这个数很大,请输出方案数除以 10^8+7的余数。
输入输出样例
示例
输入
4 10 2 3
输出
2
样例说明
这两个数列分别是 2 4 1 3 和 7 4 1 -2。
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
解题思路:
用n个数之和为s,第i个数到第i+1个数有两种情况:1.-a 2.+b 求满足n个数之和为s的方案的数量,我们可以用动态规划,开辟一个二维数组arr,行i+1表示已经选了的数的个数,列j表示放入的所有数据与第一项的差值的和对n取模的值,从后面往前推,每放进一个数进行一次状态转移,状态转移的时候注意数据的差值的变化进行状态转移,因为和值可能为负数,那我们在取模的时候取完一次+n再取一次即可就不会出现负数情况,状态转移式:
arr[i][j] = (arr[i-1][((j-a*(n-i))%n+n)%n] + arr[i-1][((j+b*(n-i))%n+n)%n]) % mod
因为S%n == [(n-1)d1 + (n-2)d2 + (n-3)d3 + ... + dn-1]%n,那我们直接输出arr中取n个数(此时的行为n-1)的时候取模值(列)为((s%n)+n)%n的值
代码:
package 蓝桥杯31天真题冲刺.Day14;
import java.io.*;
/**
* @author snippet
* @data 2023-03-17
* 波动数列-蓝桥云课
*/
// 动态规划
public class T4_波动数列 {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
static int n,s,a,b;// n表示整个数列的个数 s表示数列所有数据的和值 a的值:(前一项-a == 后一项) b的值:(前一项+b == 后一项)
static int[][] arr;// 二维数组arr的行i+1表示放入的数据的个数 j表示放入的所有数据与第一项的差值的和对n取模的值
static int mod = (int) (1e8+7);
public static void main(String[] args) throws IOException {
String[] str = br.readLine().split(" ");
n = Integer.parseInt(str[0]);
s = Integer.parseInt(str[1]);
a = Integer.parseInt(str[2]);
b = Integer.parseInt(str[3]);
arr = new int[n+1][n+1];
// 放入第一个数
arr[0][0] = 1;
// 一共放入n个数 i表示前面一共有多少个数
for (int i = 1; i < n; i++) {
// 因为是对n取模,则取模得到的值在区间[0,n)中
for (int j = 0; j < n; j++) {
// 因为我们不知道每一次前面的选择是+a还是-b
// 那我们就只可以从后面来计算前面的数据的可能情况的方案和
// j表示的是数列的差值的和 对n取模 得到的值
// 因为是从后面往前推 那+a就变成-a;-b就变成+b
// 因为数据存在负值 那我们将第一次取模得到的数据+n再对n取模 得到的数据的相对位置是不变的
arr[i][j] = (arr[i-1][((j-a*(n-i))%n+n)%n] + arr[i-1][((j+b*(n-i))%n+n)%n]) % mod;
}
}
// 因为 S%n == [(n-1)d1 + (n-2)d2 + (n-3)d3 + ... + dn-1]%n
pw.println(arr[n-1][((s%n)+n)%n]);
pw.flush();
br.close();
}
}