A - AABCC
题义:
题解:
读完题目可以想到直接暴力,但是肯定超时别想了。
因为 a b c 都是素数,所以我们可以先求出所有的素数 进行减少循环的次数,然后遍历。在遍历过程中,我们也要去进行剪枝 ,如果说 a 的五次方大于了目标值,那后面肯定就都大于了,以此类推。
import java.util.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);long n = sc.nextLong();// 求素数 并放入集合中ArrayList<Integer> primeNumbers = new ArrayList<>(1000);getPrimeNumbers(n, primeNumbers);// 使用 HashSet 集合存储答案HashSet<Long> ans = new HashSet<>();long a, b, c, e;// 遍历所有可能 并使用if剪枝,如果说 a 的五次方大于了目标值,那后面肯定就都大于了for (int i = 0; i < primeNumbers.size(); i++) {a = primeNumbers.get(i);if (a * a * a * a * a > n)break;for (int j = i + 1; j < primeNumbers.size(); j++) {b = primeNumbers.get(j);if (a * a * b * b * b > n)break;for (int k = j + 1; k < primeNumbers.size(); k++) {c = primeNumbers.get(k);e = a * a * b * c * c;if (e <= n)ans.add(e);elsebreak;}}}// Set 集合中的个数 为答案的数量System.out.println(ans.size());}// 求素数,埃筛private static void getPrimeNumbers(long n, ArrayList<Integer> primeNumbers) {int len = (int) Math.sqrt(n) >> 1;// 初始化素数int[] temp = new int[len];temp[0] = 1;temp[1] = 1;for (int i = 2; i < len; i++) {if (temp[i] == 0) {for (int j = i * 2; j < len; j += i) {temp[j] = 1;}primeNumbers.add(i);}}}
}
B - Same Map in the RPG World
题义:
题解:
我们还是可以第一眼想到暴力求解,但是这个暴力不能太直接了。
我们可以把每一个点,当作是起点,然后根据这个点 去和 B 矩阵从(0, 0)开始比对。完全相同则为Yes。
import java.util.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int h = sc.nextInt();int w = sc.nextInt();sc.nextLine();// 存放数据矩阵char[][] a = new char[50][50];char[][] b = new char[50][50];for (int i = 0; i < h; i++)a[i] = sc.nextLine().toCharArray();for (int i = 0; i < h; i++)b[i] = sc.nextLine().toCharArray();// 先设为 false,遍历每一个点,把这些点当作为起点,然后和 B 矩阵对比boolean k = false;for (int i = 0; i < h; i++) {for (int j = 0; j < w; j++) {if (judge(a, b, i, j, h)) {k = true;break;}}}if (k)System.out.println("Yes");elseSystem.out.println("No");}static boolean judge(char[][] a, char[][] b, int x, int y, int h) {int t = y;for (int i = 0; i < h; i++) {// 遍历 如果 x 大于了高度 h 则说明 A 矩阵已经从起点遍历到了最后 需要把 x+i 放到第一行x = x + i >= h ? x - h : x;y = t;for (int j = 0; j < a[i].length; j++) {// y 同理y = y + j >= a[i].length ? y - a[i].length : y;if (a[x + i][y + j] != b[i][j]) {return false;}}}return true;}
}
C - Cross
题义:
题解:
遍历每一个点,把该点当作 X 图形的中心,求出这个点最大的 X 图形长度。既然是求最大,那么就不用考虑是否会交叉等问题。
import java.util.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);h = sc.nextInt();w = sc.nextInt();sc.nextLine();for (int i = 0; i < h; i++) mp[i] = sc.nextLine().toCharArray();// 遍历每一个点当作中心for (int i = 0; i < h; i++)for (int j = 0; j < w; j++)if (mp[i][j] == '#')fun(i, j);// 输出答案for (int i = 1; i <= Math.min(h, w); i++) System.out.print(ans[i] + " ");}static int[] ans = new int[110];static char[][] mp = new char[110][100];static int h, w;// 求以(x, y)为中心,最大的 X 图像为多大static void fun(int x, int y) {int i = 1;while (true) {// 越界 就退出循环if (x - i < 0 || y - i < 0 || x + i >= h || y + i >= w)break;// 不能抵达 就退出循环if (mp[x - i][y - i] != '#' || mp[x + i][y - i] != '#' || mp[x - i][y + i] != '#' || mp[x + i][y + i] != '#')break;i++;}// 存进答案数组中ans[i - 1]++;}
}
D - Find by Query
题解:
交互题。
已知 s1 = 0,sn = 1。则不管中间是什么值,肯定会有一个分界的点,我们就是要求出这个点(任求一个)。很容易我们想到二分的方法,注意临界条件和判断条件。
import java.util.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();// 二分 每次询问中间的值,如果是 0,则往右边靠,因为最右边是 1。// 那肯定有一个分界点。如果是 1,同理。int l = 1, r = n, mid, res;while (l <= r) {mid = (l + r) / 2;System.out.println("?" + mid);res = sc.nextInt();if (res == 0)l = mid + 1;elser = mid - 1;}System.out.println("!" + r);}
}
E - Dango
题义:
题解:
简单模拟题,注意细节就好了。
import java.util.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();sc.nextLine();String s = sc.nextLine();int ans = -1, l, r = -1;for (int i = 0; i < s.length(); i++) {// 如果该点为 -,则看是否为最大值 尝试存入答案if (s.charAt(i) == '-') {l = r;r = i;ans = Math.max(ans, r - l - 1);}}// 特殊情况,当 r == -1 则说明没有 -// 不为 r != -1 则求 从字符串最后到 倒数第一个 - 的距离 也可能为答案if (r != -1)ans = Math.max(ans, s.length() - r - 1);// 如果答案为 0,则没有 o,输出 -1if (ans == 0)ans--;System.out.println(ans);}
}
F - Cards Query Problem
题义:
题解:
分别使用两个集合去存储数据。使用 ArrayList 集合当作一个盒子,把元素存进该集合中。
使用 TreeSet 集合,存储对应下标卡片,在哪些盒子中存在。(其中 因为实现了 Set 接口 所以可以自动去重,又是 TreeSet 可以自动排序)
import java.util.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int q = sc.nextInt();int i, x;// 创建两个集合,分别存放一个盒子中有的卡片ArrayList<ArrayList<Integer>> arrayLists = new ArrayList<>(n);// 存放一个卡片的值 在哪些盒子中存在于 哪些盒子中,因为需要去重所以选择Set集合,又因为TreeSet自带排序ArrayList<TreeSet<Integer>> treeSets = new ArrayList<>(200010);for (i = 0; i < 200010; i++)treeSets.add(new TreeSet<>());for (i = 0; i < n; i++)arrayLists.add(new ArrayList<>(100));while (q-- != 0) {switch (sc.nextInt()) {case 1:x = sc.nextInt();i = sc.nextInt();// 放入对应的集合treeSets.get(x).add(i);arrayLists.get(i - 1).add(x);break;case 2:i = sc.nextInt();// 排序后输出 盒子中的全部卡片ArrayList<Integer> integers = arrayLists.get(i - 1);Collections.sort(integers);for (Integer integer : integers)System.out.print(integer + " ");System.out.println();break;case 3:x = sc.nextInt();// 输出对应卡片的集合里的 所有盒子(已经自动排序了)TreeSet<Integer> treeSet = treeSets.get(x);for (Integer integer : treeSet)System.out.print(integer + " ");System.out.println();break;}}}
}
H - Writing a Numeral
题义:
题解:
全程使用一个 long 类型维护。
操作一:加一个数后,进行对这个值取模。
操作二:删除最前面的数,删除时考虑 当时的位数(队列的位数),而不是维护的数值的位数。因为维护的数会被取模。而在进行减的时候,也要先进行取模,否则可能会数字过大,这里还可以使用预处理进行减少计算的时间与次数。
操作三:输出维护的这个数值。
import java.util.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);long n = sc.nextLong();// 需要 mod 的值final int INF = 998244353;// 初始化数值为 1,待会用来做乘法long ans = 1;// 预处理long[] div = new long[600005];div[0] = 1;for (int i = 1; i < 600005; i++)div[i] = div[i - 1] * 10 % INF;// 使用 LinkedList 集合来存储各个位上的数字,方便尾插和弹出队头LinkedList<Integer> linkedList = new LinkedList<>();linkedList.add(1);for (long i = 0; i < n; i++) {switch (sc.nextInt()) {case 1:// 插入队尾int a = sc.nextInt();linkedList.addLast(a);ans = ans * 10 + a;ans = myMod(ans, INF);break;case 2:// 移除头节点,并将维护的数字减去这个头节点对应的值Integer first = linkedList.removeFirst();ans -= (long) first * div[linkedList.size()];// 减去之后可能为负数,改为自己定义的 mod 方法ans = myMod(ans, INF);break;case 3:// 输出维护的数值System.out.println(ans);break;}}}// mod 可能为负数,自定义 modstatic long myMod(long x, long mod) {x %= mod;while (x < 0)x += mod;return x;}
}
J - M<=ab
题义:
题解:
阅读完题目很容易想到暴力,也就是从 M 开始,一个一个试看是否有两个数字可以相乘的值为它,并且这两个值都小于 N。但是肯定超时。。。
改变思路,我们可以从 1 开始 (设为 i),求出一个与 i 相乘 大于等于 M 且最接近 M 的值。推导出
(m + i - 1) / i;
为什么要 +i ?因为 M / i * i 的值可能会小于 M,加了 i 之后,计算出来的结果一定会使得 求出来的值 乘以 i 大于等于 M。
import java.util.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);long n = sc.nextLong();long m = sc.nextLong();long k, ans = Long.MAX_VALUE;for (long i = 1; i <= n; i++) {// 求出一个 与 i 相乘 大于等于 M 的值,且该值为最接近 M 的k = (m + i - 1) / i;// 剪枝,如果 i 大于了 k 的话,其实后面的值 之前都遍历过了,break 跳出if (i <= k) {// 如果 k 在答案的范围内(1-n),则对比一下结果if (k <= n)ans = Math.min(ans, i * k);} else {break;}}if (ans == Long.MAX_VALUE)System.out.println(-1);elseSystem.out.println(ans);}
}
K - Gap Existence
题义:
题解:
使用 HashSet 进行存储数据(包含了去重、快速查找功能)。
import java.util.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int x = sc.nextInt();// 使用 HashSet 存储,满足题目的快速查找(hash值)和去重剪枝需求HashSet<Integer> hashSet = new HashSet<>(n);for (long i = 0; i < n; i++)hashSet.add(sc.nextInt());// 判断是否含有这个值,a - x 的值boolean k = false;for (Integer a : hashSet) {if (hashSet.contains(a - x)) {k = true;break;}}if (k)System.out.println("Yes");elseSystem.out.println("No");}
}
L - 2xN Grid
题义:
题解:
简单模拟题。
import java.util.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);long len = sc.nextLong();long n1 = sc.nextLong();long n2 = sc.nextLong();ArrayList<Node> nodes = new ArrayList<>();for (int i = 0; i < n1; i++)nodes.add(new Node(sc.nextLong(), sc.nextLong()));int now = 0;long ans = 0, x = 0, l = 0, xx = 0, ll = 0;for (int i = 0; i < n2; i++) {x = sc.nextLong();l = sc.nextLong();// 将 B 序列的值 循环消耗完while (l != 0) {if (ll == 0) {Node node = nodes.get(now++);xx = node.x;ll = node.l;}if (l <= ll) {if (x == xx)ans += l;ll -= l;l = 0;} else {if (x == xx)ans += ll;l -= ll;ll = 0;}}}System.out.println(ans);}static class Node {long x, l;Node(long x, long l) {this.x = x;this.l = l;}}
}
M - Bank
题义:
题解:
该题目对 Java 选手不太友好,这样都超时。
因为,题目只有操作二可以删除元素,而在删除之前肯定会添加该元素,所以操作一都不用管。操作三时,如果 bool 值为 true 则说明该值已经被删除了,则 ++ 判断下一个值。
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int q = sc.nextInt();// 创建一个 bool 数组判断是否删除了该元素boolean[] booleans = new boolean[n+1];int last = 1;for (int i = 0; i < q; i++) {switch (sc.nextInt()) {case 2:// 操作二 删除一个元素int a = sc.nextInt();booleans[a] = true;break;case 3:// 操作三 输出一个最小的没有被删除的元素while (booleans[last])last ++;System.out.println(last);break;}}}
}