前言
整体评价
这场题变多了,但是难度不如上周,G题是道经典的博弈题,H题是一道有趣的图论题,需要优化(过河拆桥)。
这篇主要写A~D的题解,下一篇写E-H的题解。
A. 双十一的祈祷
Q: 的各位数是?
以双十一为主题的签到题,答案自然是1
如果不是11为底,而是其他数字,那可以用快速幂,也可以用找循环节的思路来求解
public class Main {
public static void main(String[] args) {
System.out.println(1);
}
}
ps:
粗略地写下 找循环节的函数,有点像基环树
先找到环的入口,然后把环提取出来
当然这边要分类考虑
- 一个在环入口之前
- 一个在环内部循环
public static int getLoop(int b, int v) {
// 相当于找到环的入口
Map<Integer, Integer> hash = new HashMap<>();
int r = 1;
int i = 0;
while (!hash.containsKey(r)) {
// 在环的入口前遇到,提前推出
if (v == i) return r;
hash.put(r, i++);
r = r * b % 10;
}
// 提取环
List<Integer> arr = new ArrayList<>();
int s = r;
do {
arr.add(s);
s = s * b % 10;
} while (s != r);
int idx = (v - hash.get(r)) % arr.size();
return arr.get(idx);
}
B. 疯狂的促销
Q: 比价系统,对于一个商品,淘宝/京东/拼多多都有自己的优惠策略,求购买多个商品的全场最低价(好耳熟的口号)?
按需求描述,模拟即可
import java.io.BufferedInputStream;
import java.util.Scanner;
public class Main {
static long minPrice(int v) {
int p1 = v >= 500 ? (v - v / 10) : v;
int p2 = v >= 1000 ? v - 150 : v;
int p3 = v == 1111 ? 0 : (v - v / 20);
return Math.min(p1, Math.min(p2, p3));
}
public static void main(String[] args) {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
int n = sc.nextInt();
long acc = 0;
for (int i = 0; i < n; i++) {
int v = sc.nextInt();
acc += minPrice(v);
}
System.out.println(acc);
}
}
C. 被替换的身份证
Q: 每个选手各2张牌,看谁先出完?
分类讨论即可
- 先手方是对子,王炸
- 先手方的有一张单牌最大,且后手方没王炸
import java.io.*;
import java.util.*;
public class Main {
static boolean isPair(char c1, char c2) {
return c1 == c2;
}
static boolean isBomb(char c1, char c2) {
if (c1 == 'M' && c2 == 'F') return true;
if (c1 == 'F' && c2 == 'M') return true;
return false;
}
static int maxCard(char[] str) {
String p = "3456789XJQKA2MF";
return Math.max(p.indexOf(str[0]), p.indexOf(str[1]));
}
public static void main(String[] args) {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
int t = sc.nextInt();
while (t -- > 0) {
char[] card1 = sc.next().toCharArray();
char[] card2 = sc.next().toCharArray();
if (isPair(card1[0], card1[1]) || isBomb(card1[0], card1[1])) {
System.out.println("ShallowDream");
} else {
int p1 = maxCard(card1);
int p2 = maxCard(card2);
if (p1 >= p2 && !isBomb(card2[0], card2[1])) {
System.out.println("ShallowDream");
} else {
System.out.println("Joker");
}
}
}
}
}
D. 迷宫逃脱
Q: N*M的矩阵中,只能向下向右,且遇到相邻互质,需要消耗钥匙,求在最多消耗Q把钥匙的前提下,路径累计和最大。
这是一道经典的递推DP题
令 dp[i][j][s], 为i,j位置下消耗了s把钥匙的最大路径和
则 dp[i][j][s] = max(dp[i - 1][j][s1],dp[i][j - 1][s2]) + grid[i][j]
这边的s1,s2和 gcd(grid[i - 1][j], grid[i][j]) 有关,如果互质,则s1 = s - 1, 否则 s1 = s, s2亦是如此
这题需要快读板子
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
static long gcd(long a, long b) {
return b == 0 ? a : gcd(b, a % b);
}
public static void main(String[] args) {
AReader sc = new AReader();
int n = sc.nextInt(), m = sc.nextInt(), k = sc.nextInt();
long[][] grid = new long[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
grid[i][j] = sc.nextInt();
}
}
long inf = Long.MIN_VALUE / 10;
long[][][] dp = new long[n][m][k + 1];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
Arrays.fill(dp[i][j], inf);
}
}
// 左上角的位子
for (int i = 0; i <= k; i++) {
dp[0][0][i] = grid[0][0];
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
for (int t = 0; t <= k; t++) {
if (dp[i][j][t] == inf) continue;
if (i + 1 < n) {
long x = gcd(grid[i][j], grid[i + 1][j]);
if (x > 1) {
dp[i+1][j][t] = Math.max(dp[i+1][j][t], dp[i][j][t] + grid[i + 1][j]);
} else if (t < k) {
dp[i+1][j][t + 1] = Math.max(dp[i+1][j][t + 1], dp[i][j][t] + grid[i + 1][j]);
}
}
if (j + 1 < m) {
long x = gcd(grid[i][j], grid[i][j + 1]);
if (x > 1) {
dp[i][j + 1][t] = Math.max(dp[i][j + 1][t], dp[i][j][t] + grid[i][j + 1]);
} else if (t < k) {
dp[i][j + 1][t + 1] = Math.max(dp[i][j + 1][t + 1], dp[i][j][t] + grid[i][j + 1]);
}
}
}
}
}
long ans = inf;
for (int i = 0; i <= k; i++) {
ans = Math.max(ans, dp[n - 1][m - 1][i]);
}
System.out.println(ans <= 0 ? -1 : ans);
}
static
class AReader {
private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
private StringTokenizer tokenizer = new StringTokenizer("");
private String innerNextLine() {
try {
return reader.readLine();
} catch (IOException ex) {
return null;
}
}
public boolean hasNext() {
while (!tokenizer.hasMoreTokens()) {
String nextLine = innerNextLine();
if (nextLine == null) {
return false;
}
tokenizer = new StringTokenizer(nextLine);
}
return true;
}
public String nextLine() {
tokenizer = new StringTokenizer("");
return innerNextLine();
}
public String next() {
hasNext();
return tokenizer.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
// public BigInteger nextBigInt() {
// return new BigInteger(next());
// }
// 若需要nextDouble等方法,请自行调用Double.parseDouble包装
}
}