A 组队
作为篮球队教练,你需要从以下名单中选出 1 号位至 5 号位各一名球员,组成球队的首发阵容。
每位球员担任 1 号位至 5 号位时的评分如下表所示。
请你计算首发阵容 1号位至 5 号位的评分之和最大可能是多少?
1 97 90 0 0 0
2 92 85 96 0 0
3 0 0 0 0 93
4 0 0 0 80 86
5 89 83 97 0 0
6 82 86 0 0 0
7 0 0 0 87 90
8 0 97 96 0 0
9 0 0 89 0 0
10 95 99 0 0 0
11 0 0 96 97 0
12 0 0 0 93 98
13 94 91 0 0 0
14 0 83 87 0 0
15 0 0 98 97 98
16 0 0 0 93 86
17 98 83 99 98 81
18 93 87 92 96 98
19 0 0 0 89 92
20 0 99 96 95 81
解析
采用 DFS 枚举每个位置运动员编号
注意第一列是编号,可以把文本复制粘贴到word里,然后按住Alt + shift就可以删除第一列了
代码
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class Main {
static int[][] a = new int[25][10];
static boolean[] vis = new boolean[25];
static int max = Integer.MIN_VALUE; // Integer.MIN_VALUE 代表Integer的最小值-2147483648
public static void main(String[] args) throws FileNotFoundException {
// TODO Auto-generated method stub
Scanner inScanner = new Scanner(new File("src/data.txt")); // 读取data.txt的内容
for (int i = 0; i < 20; i++)
for (int j = 0; j < 5; j++) {
a[i][j] = inScanner.nextInt(); // 存入数组
}
DFS(0, 0);
System.out.println(max);
}
static void DFS(int count, int sum) {
// count记录选择的人数,最终只能5人,sum表示当前的权值
if (count == 5) {
// 选择出了5人
if (sum > max) {
max = sum; // 得到更大的sum权值,更新
}
return;
}
for (int i = 0; i < 20; i++) {
if (!vis[i]) {
// 当前号的运动员尚未选择
vis[i] = true; // 标记当前运动员已选择
DFS(count + 1, sum + a[i][count]);
vis[i] = false; // 回溯
}
}
}
}
B 不同字串
一个字符串的非空子串是指字符串中长度至少为 1 的连续的一段字符组成的串。
例如,字符串aaab 有非空子串a, b, aa, ab, aaa, aab, aaab,一共 7 个。
注意在计算时,只算本质不同的串的个数。请问,字符串0100110001010001 有多少个不同的非空子串?
解析
采用 map 记录已有的字串,最后统计 map 中有多少个不同的键值对
代码
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int ans=0;
Map<String, Integer> map=new HashMap<String, Integer>();
String tempString="0100110001010001";
for(int i=0;i<tempString.length();i++) {
for(int j=i+1;j<=tempString.length();j++) {
String temp=tempString.substring(i, j);
if(map.get(temp)==null) {
map.put(temp, 1);
ans++;
}
}
}
System.out.println(ans);
scanner.close();
}
}
C 数列求值
给定数列 1, 1, 1, 3, 5, 9, 17, …,从第 4 项开始,每项都是前 3 项的和。
求第 20190324 项的最后 4 位数字。
解析
因为只用记录最后4位数字,所以一直用的存储数字都对 10000 取余
代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
long i=1,j=1,k=1;
long num;
for(int start=4;start<=20190324;start++) {
num=i+j+k;
i=j%10000;
j=k%10000;
k=num%10000;
}
System.out.println(k);
scanner.close();
}
}
D 数的分解
把 2019 分解成 3 个各不相同的正整数之和,并且要求每个正整数都不包含数字 2 和 4,一共有多少种不同的分解方法?
注意交换 3 个整数的顺序被视为同一种方法,例如 1000+1001+18 和1001+1000+18 被视为同一种。
解析
挨个枚举
代码
import java.security.Principal;
import java.util.Scanner;
public class Main {
static boolean isprim(int num) {
while(num!=0) {
if(num%10==2||num%10==4) {
return false;
}
num/=10;
}
return true;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int ans=0;
for (int i = 1; i < 2019; i++) {
for (int j = i; j < 2019; j++) {
if(i==j) {
continue;
}
for (int k = j; k < 2019; k++) {
if(k==i||k==j) {
continue;
}
if(isprim(i)&&isprim(j)&&isprim(k)&&i+j+k==2019)
{
ans++;
System.out.println(i + " " + j + " " + k);
}
}
}
}
System.out.println(ans);
scanner.close();
}
}
E 迷宫
下图给出了一个迷宫的平面图,其中标记为 1 的为障碍,标记为 0 的为可以通行的地方。
010000
000100
001001
110000
迷宫的入口为左上角,出口为右下角,在迷宫中,只能从一个位置走到这个它的上、下、
左、右四个方向之一。 对于上面的迷宫,从入口开始,可以按DRRURRDDDR 的顺序通过迷宫,
一共 10 步。其中 D、U、L、R 分别表示向下、向上、向左、向右走。 对于下面这个更
复杂的迷宫(30 行 50 列),请找出一种通过迷宫的方式, 其使用的步数最少,在步数
最少的前提下,请找出字典序最小的一个作为答案。 请注意在字典序中D<L<R<U。
解析
BFS 算法的使用
代码
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main {
static Scanner scanner = new Scanner(System.in);
static int[][] stepArr = {
{
1, 0 }, {
0, 1 }, {
0, -1 }, {
-1, 0 } }; // D R L U
static String[] direction = {
"D", "R", "L", "U" }; // 与stepArr对应
static int[][] map = new int[30][50]; // 记录地图
static boolean[][] visit = new boolean[30][50]; // 记录是否访问
// 构造结点类
public static class P {
public int x;
public int y;
public String roadString;
P(int x, int y) {
this.x = x;
this.y = y;
}
}
public static void main(String[] args) {
for (int i = 0; i < 30; i++) {
String string = scanner.nextLine();
for (int j = 0; j < 50; j++) {
map[i][j] = string.charAt(j) - '0';
}
}
BFS();
}
static void BFS() {
Queue<P> queue = new LinkedList<P>();// 构造队列
P start = new P(0, 0); // 起点为左上角(0,0)
start.roadString = "";
visit[0][0] = true;
queue.offer(start); // 将起点压入队列
while (!queue.isEmpty()) {
// 队列不空执行
P now = queue.poll(); // 获取并移除此队列的头,如果此队列为空,则返回 null。
if (now.x == 29 && now.y == 49) {
// 到达终点
System.out.println(now.roadString);
return;
} else {
for (int i = 0; i < 4; i++) {
// 遍历四个方向
int newX, newY;
newX = now.x + stepArr[i][0];
newY = now.y + stepArr[i][1];
if (newX >= 0 && newX < 30 && newY >= 0 && newY < 50 && !visit[newX][newY]
&& map[newX][newY] == 0) {
// 下一个节点没越界、没访问、是可通过的
P next = new P(newX, newY);
next.roadString = now.roadString + direction[i];
visit[newX][newY] = true; // 标记此点已访问
queue.offer(next);
}
}
}
}
}
}
F 特别数的和
小明对数位中含有 2、0、1、9 的数字很感兴趣(不包括前导 0),
在 1 到40 中这样的数包括 1、2、9、10 至 32、39 和 40,共 28 个,他们的和是 574。
请问,在 1 到 n 中,所有这样的数的和是多少?
Input
输入一行包含一个整数 n。
Output
输出一行,包含一个整数,表示满足条件的数的和。
解析
枚举即可
代码
import java.util.Scanner;
public class Main {
static boolean isprim(int n) {
while (n != 0) {
if (n % 10 == 2 || n % 10 == 0 || n % 10 == 1 || n % 10 == 9) {
return true;
} else {
n /= 10;
}
}
return false;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scanner = new Scanner(System.in);
int n;
n = scanner.nextInt();
int ans = 0;
for (int i = 1; i <= n; i++) {
if (isprim(i)) {
ans += i;
}
}
System.out.println(ans);
scanner.close();
}
}
G 外卖店优先级
“饱了么”外卖系统中维护着 N 家外卖店,编号 1 ∼ N。
每家外卖店都有一个优先级,初始时 (0 时刻) 优先级都为 0。
每经过 1 个时间单位,如果外卖店没有订单,则优先级会减少 1,最低减到 0;
而如果外卖店有订单,则优先级不减反加,每有一单优先级加 2。
如果某家外卖店某时刻优先级大于 5,则会被系统加入优先缓存中;
如果优先级小于等于 3,则会被清除出优先缓存。
给定 T 时刻以内的 M 条订单信息,请你计算 T 时刻时有多少外卖店在优先缓存中。
Input
第一行包含 3 个整数 N、M 和 T。
以下 M 行每行包含两个整数 ts 和 id,表示 ts 时刻编号 id 的外卖店收到一个订单。
Output
输出一个整数代表答案。
解析
将每一个订单首先按照时间顺序排序,再按照店铺顺序排序。
遍历一遍排序后的订单。记录每个店铺上一次订单的时间 last 。每次遍历时,便可求的这次订单距离上次订单中间有多少个单位时间没有订单,需要减去。减去以后再统计在此时刻店铺的订单数,把得分加上此时可的订单得分。按照这种顺序直至遍历完。最后还需计算最受一次订单的下单时间与要求的 T 时刻之间的间隔,同样,间隔时间也得减去
代码
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Scanner;
public class Main {
static Scanner scanner = new Scanner(new BufferedInputStream(System.in));// 大量数据时提高读取速率
static final int MAX = 100010;
static class Order {
// 订单类
public int ts;
public int id;
public Order(int ts, int id) {
// TODO Auto-generated constructor stub
this.ts = ts;
this.id = id;
}
}
static ArrayList<Order> list = new ArrayList<>();
static int N;
static int M;
static int T;
static int[] last = new int[MAX]; // 上一次有订单的时间
static int[] score = new int[MAX]; // 每个店铺的得分
static boolean[] st = new boolean[MAX]; // 记录是否存在于优先队列中
public static void main(String[] args) {
N = scanner.nextInt();
M = scanner.nextInt();
T = scanner.nextInt();
int[] shop = new int[N + 1]; // 记录店铺
for (int i = 1; i <= N; i++) {
shop[i] = 0;
}
for (int i = 0; i < M; i++) {
list.add(new Order(scanner.nextInt(), scanner.nextInt()));
}
Collections.sort(list, new Comparator<Order>() {
// 排序实现
public int compare(Order order1, Order order2) {
if (order1.ts != order2.ts)
return order1.ts > order2.ts ? 1 : -1;
else {
return order1.id > order2.id ? 1 : -1;
}
}
});
// 遍历每一个订单
for (int i = 0; i < M; i++) {
int j = i;
while (j < M && list.get(i).id == list.get(j).id && list.get(i).ts == list.get(j).ts) // 同一时间同一店铺
j++; // 记录连续订单的最后一个的下标(方便计算最终该时刻与上一次订单之间的数目)
int t = list.get(i).ts; // 当前连续订单的时刻
int id = list.get(i).id; // 当前连续订单所属店铺
score[id] -= t - last[id] - 1; // 减去当前时刻距离上一次时刻没有订单的单位时间得分
if (score[id] < 0)
score[id] = 0;
if (score[id] <= 3)
st[id] = false;
last[id] = t; // 更新上一次订单的时间
//上面是处理t时刻之前的减, 下面处理t时刻的加
score[id] += (j - i) * 2; // 加上当前时刻的订单得分
if (score[id] > 5)
st[id] = true;
i=j-1; // 下一次遍历从 j 开始进行(后面会执行 i++ ,所以得减 1)
}
// 考虑店铺最后一次有订单时刻却还未到 T 的情况(此时订单已经遍历完,也可以理解为 T 大于最后一个订单的 ts)
for(int i=1;i<=N;i++) {
if(last[i]<T) {
score[i]-=T-last[i];
if(score[i]<=3) {
st[i]=false;
}
}
}
// 统计加入优先队列的个数
int count=0;
for(int i=1;i<=N;i++) {
if(st[i]) {
count++;
}
}
System.out.println(count);
}
}
H 人物相关性分析
小明正在分析一本小说中的人物相关性。
他想知道在小说中 Alice 和 Bob有多少次同时出现。
更准确的说,小明定义 Alice 和 Bob“同时出现”的意思是:在小说文本中 Alice 和 Bob 之间不超过 K 个字符。
例如以下文本:This is a story about Alice and Bob. Alice wants to send a private message to Bob.
假设 K = 20,则 Alice 和 Bob 同时出现了 2 次,分别是”Alice and Bob”和”Bob. Alice”。
前者 Alice 和 Bob 之间有 5 个字符,后者有 2 个字符。
注意:
-
- Alice 和 Bob 是大小写敏感的,alice 或 bob 等并不计算在内。
-
- Alice 和 Bob 应为单独的单词,前后可以有标点符号和空格,但是不能有字母。例如 Bobbi 并不算出现了 Bob。
Input
第一行包含一个整数 K。
第二行包含一行字符串,只包含大小写字母、标点符号和空格。长度不超过 1000000。
Output
输出一个整数,表示 Alice 和 Bob 同时出现的次数。
解析
采用两个动态数组存储分别存储每个 Alice 和 Bob 的首字母下标,最后分别统计出每个 Alice 的前面 K 个范围的区间里有多少个 Bob、每个 Bob 的前面 K 个范围的区间里有多少个 Alice ,最后将两个统计的结果相加即为最终答案
代码
import java.io.BufferedInputStream;
import java.util.Scanner;
import java.util.Vector;
public class Main {
static Scanner scanner = new Scanner(new BufferedInputStream(System.in));
static Vector<Integer> Alice = new Vector<>(); // 创建动态数组存储名字出现的位置
static Vector<Integer> Bob = new Vector<>();
static int K;
static String string;
// 检查字符是否为字母,因为名字的前后不能有字母
static boolean check(char c) {
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
return false; // 是字母,返回false
else
return true; // 是符号,返回true
}
public static void main(String[] args) {
K = scanner.nextInt();
scanner.nextLine(); // 读取多余的换行符
string = scanner.nextLine(); // 换行符为结束标志
// 遍历string字符串找到所有 Alice 的下标
for (int i = 0; i + 5 <= string.length(); i++) {
if ((i == 0 || check(string.charAt(i - 1))) && (i + 5 == string.length() || check(string.charAt(i + 5)))) {
// 检查是否前后字符满足规格要求
if (string.substring(i, i + 5).equals("Alice")) // 判断得到的字符是否为 Alice
Alice.add(i);
}
}
// 遍历string字符串找到所有 Bob 的下标
for (int i = 0; i + 3 <= string.length(); i++) {
if ((i == 0 || check(string.charAt(i - 1))) && (i + 3 == string.length() || check(string.charAt(i + 3)))) {
// 检查是否前后字符满足规格要求
if (string.substring(i, i + 3).equals("Bob")) // 判断得到的字符是否为 Bob
Bob.add(i);
}
}
long res = 0; // 记录答案总数
// 计算每一个 Alice 前面有多少个 Bob 并求和
for (int i = 0; i < Alice.size(); i++) {
int l = 0, r = -1;
while (r + 1 < Bob.size() && Alice.get(i) > Bob.get(r + 1))
r++; // 找到在K的范围内的最后一个Bob
while (l <= r && Alice.get(i) > Bob.get(l) + 3 + K)
l++; // 找到在K的范围内的第一个Bob
res += r - l + 1;
}
// 计算每一个 Bob 前面有多少个 Alice 并求和
for (int i = 0; i < Bob.size(); i++) {
int l = 0, r = -1;
while (r + 1 < Alice.size() && Bob.get(i) > Alice.get(r + 1))
r++; // 找到在K的范围内的最后一个Alice
while (l <= r && Bob.get(i) > Alice.get(l) + 5 + K)
l++; // 找到在K的范围内的第一个Alice
res += r - l + 1;
}
System.out.println(res);
}
}
I 后缀表达式
给定 NN 个加号、MM 个减号以及 N + M + 1N+M+1 个整数 A_1, A_2, · · · , A_{N+M+1}A1,A2,⋅⋅⋅,A**N+M+1,
小明想知道在所有由这 NN 个加号、MM 个减号以及 N + M + 1N+M+1 个整数凑出的合法的后缀表达式中,
结果最大的是哪一个?请你输出这个最大的结果。
例如使用1 2 3 + -123+−,则 “2 3 + 1 -23+1−” 这个后缀表达式结果是 44,是最大的。
Input
第一行包含两个整数 NN 和 MM。
第二行包含 N + M + 1N+M+1 个整数 A_1, A_2, · · · , A_{N+M+1}A1,A2,⋅⋅⋅,A**N+M+1。
Output
输出一个整数,代表答案。
解析
情况分为三种情况考虑
负数与负号的数量形同:所有数的绝对值相加
负数多于负号数目:A 一般情况下与第一种情况相同,即为所有数的绝对值之和。B 当全为负数时 :所有数的绝对值之和减去2倍的最大负数。 C 当负号数量为0时:所有数直接做和即为最大值
负数少于负号数目:A 一般情况下与第一种情况相同,即为所有数的绝对值之和。 B 当没有负数时:所有数的绝对值之和加上2倍的最小正数
代码
import java.io.BufferedInputStream;
import java.util.Scanner;
public class Main {
static Scanner scanner = new Scanner(new BufferedInputStream(System.in));
static int minz = Integer.MAX_VALUE; // 记录最小正数
static int maxz = Integer.MIN_VALUE; // 记录最大负数
static long sumNum = 0; // 记录所有数绝对值之和
static long sumN = 0; // 记录所有数之和
static int countF = 0, countZ = 0; // 分别记录负数和正数的个数
static int N, M;
public static void main(String[] args) {
N = scanner.nextInt();
M = scanner.nextInt();
for (int i = 0; i <= M + N; i++) {
int temp = scanner.nextInt();
sumNum += Math.abs(temp); // 绝对值求和
sumN += temp; // 数求和
if (temp < 0) {
// 负数
countF++;
maxz = Math.max(maxz, temp); // 更新最大负数
} else {
countZ++; // 正数
minz = Math.min(minz, temp); // 更新最小正数
}
}
if (countF == M) {
// 负数个数等于减号个数
System.out.println(sumNum);
} else if (M == 0) {
// 减号个数为 0 个
System.out.println(sumN);
} else if (countF > M) {
// 负数个数大于减号个数
if (countZ == 0) {
// 全是负数
System.out.println(sumNum + 2 * maxz);
} else {
System.out.println(sumNum);
}
} else {
// 负数个数小于减号个数
if (countF == 0) {
// 负数个数为 0 个
System.out.println(sumNum - 2 * minz);
} else {
System.out.println(sumNum);
}
}
}
}
G 灵能传输
暂无,如果有好的解析文章欢迎留言推荐
结语
如果你发现文章有什么问题,欢迎留言指正。
如果你觉得这篇文章还可以,别忘记点个赞加个关注再走哦。
如果你不嫌弃,还可以关注微信公众号———梦码城(持续更新中)。
梦码在这里感激不尽!!