A:逃离高塔(AC)

这题就是简单的签到题,按照题意枚举即可。需要注意的是不要忘记用long ,用int的话会爆。
📖 ++代码示例++:
java
import java.io.*;
import java.util.*;
public class Main {
public static PrintWriter pr = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
public static Read in = new Read();
public static void main(String[] args) throws IOException{
long sum = 0;
for(long i = 1;i <= 2025;i++){
long num = i * i * i;
if(num % 10 == 3){
sum++;
}
}
System.out.println(sum);
}
}
//快读模板不必在意
class Read{
StringTokenizer st = new StringTokenizer("");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String next() throws IOException{
while(!st.hasMoreTokens()){
st = new StringTokenizer(br.readLine());
}
return st.nextToken();
}
int nextInt() throws IOException{
return Integer.parseInt(next());
}
long nextLong() throws IOException{
return Long.parseLong(next());
}
double nextDouble() throws IOException{
return Double.parseDouble(next());
}
}
📕 答案:202
B:消失的蓝宝(AC)

这题最开始尝试用暴力枚举 ,但后来跑了好长时间,又扩大了好多次范围,还是没能出结果 ,硬想了半天,觉得应该和最小公倍数有关:
要知道,要找到一个最小数,使得同时能被 a 和 b 整除,那么这个数就是 a 和 b 的最小公倍数。
题目中要求找到一个 n,满足(n + a) % b == 0 && (n + b) % a == 0,那么只要我们找到 a 和 b 的最小公倍数 c,此时c满足 c % a == c % b == 0。
那么 因为 c % a == 0 可以知道 (c - a) % a == 0。
同理 因为 c % b == 0 可以知道 (c - b) % b == 0。
假设现在我们有一个 n 满足 (n + a) % b == 0 那么 (n + a) = (c - b)
同理 (n + b) % a == 0 那么 (n + b) = (c - a)
最终得到 n = c - a - b
📖 ++代码示例++:
java
import java.io.*;
import java.util.*;
public class Main {
public static PrintWriter pr = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
public static Read in = new Read();
public static void main(String[] args) throws IOException{
long a = 20250412;
long b = 20240413;
System.out.println((a * b / gcd(a,b)) - a - b);
}
public static long gcd(long a,long b){
return b == 0 ? a : gcd(b,a % b);
}
}
class Read{
StringTokenizer st = new StringTokenizer("");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String next() throws IOException{
while(!st.hasMoreTokens()){
st = new StringTokenizer(br.readLine());
}
return st.nextToken();
}
int nextInt() throws IOException{
return Integer.parseInt(next());
}
long nextLong() throws IOException{
return Long.parseLong(next());
}
double nextDouble() throws IOException{
return Double.parseDouble(next());
}
}
📕 答案:409876661809331
C:电池分组(AC)

该题考察的是对异或操作符的理解,题中的要求是给定一个数组,让我们判断,这个数组是否能够分成两部分,使得"两部分的异或和相等"。
异或操作符:两个数字,二进制位相同为0,否则为1。
我们得清楚,不管如何划分数组,整个数组的"异或和"都是不变的,而如果数组能够分成"两个异或和相等的部分",也就意味着,最后再将这两部分的异或和进行异或,结果必然是等于0的。(数字相等,所有二进制位相同)
那么这两部分异或和的异或,所得到的结果,代表什么呢?没错,代表整个数组的异或和。
那么也就是说:如果能找到这样的两部分,则代表整个数组的异或和一定为0。
反过来想,如果一个数组的异或和为0,是否就能代表一定存在这样的两部分呢?
是一定的。因为如果一个数组异或和为0,则代表最后的一步异或和,一定会是"两部分数组的异或和"进行异或,并且"这两部分的异或和一定相等",否则就违背了"整个数组异或和为0"的前提了。
所以:如果整个数组异或和为0,则输出"YES",否则,输出"NO"。
📖 ++代码示例++:
java
import java.io.*;
import java.util.*;
public class Main {
public static PrintWriter pr = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
public static Read in = new Read();
public static void main(String[] args) throws IOException {
int t = in.nextInt();
while(t-- > 0){
int n = in.nextInt();
int[] arr = new int[n];
for(int i = 0;i < n;i++){
arr[i] = in.nextInt();
}
long sum = arr[0];
for(int i = 1;i < n;i++){
sum = arr[i] ^ sum;
}
System.out.println(sum == 0 ? "YES" : "NO");
}
}
}
class Read{
StringTokenizer st = new StringTokenizer("");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String next() throws IOException{
while(!st.hasMoreTokens()){
st = new StringTokenizer(br.readLine());
}
return st.nextToken();
}
int nextInt() throws IOException{
return Integer.parseInt(next());
}
long nextLong() throws IOException{
return Long.parseLong(next());
}
double nextDouble() throws IOException{
return Double.parseDouble(next());
}
}
D:魔法科考试(AC)

该题考察的是"素数筛法",这边我采用的是最常用的"埃氏筛",这题的数据范围是:
所以说我们只需要筛到大于40000的范围就好了,当然,即使这个范围不大,不使用优化筛法的话肯定也还是会超时的。因为使用双重for循环去检查所有魔法组合就已经有O(n^2)了~
注意:1 + 6 和 3 + 4 和 4 + 3,这种结果相同的"魔法口诀",算是同一个,不能重复计数,所以应该去重。
📖 ++代码示例++:
java
import java.io.*;
import java.util.*;
public class Main {
public static PrintWriter pr = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
public static Read in = new Read();
public static int[] zhi = new int[50100];
public static boolean[] check = new boolean[50100];
public static HashSet<Integer> set = new HashSet<>();
public static void main(String[] args) throws IOException {
shai();
int a = in.nextInt();
int b = in.nextInt();
int[] arr1 = new int[a + 1];
int[] arr2 = new int[b + 1];
for(int i = 0;i < a;i++){
arr1[i] = in.nextInt();
}
for(int i = 0;i < b;i++){
arr2[i] = in.nextInt();
}
int max = 0;
for(int i = 0;i < a;i++){
for(int j = 0;j < b;j++){
int num = arr1[i] + arr2[j];
if(num <= a + b && zhi[num] == 1){
if(!set.contains(num)){
set.add(num);
max++;
}
}
}
}
System.out.println(max);
}
public static void shai(){
for(int i = 2;i < 50049;i++){
//未被筛出
if(!check[i]){
//标记为质数
zhi[i] = 1;
//将i的倍数都筛出
for(int j = i;j < 50049;j += i){
check[j] = true;
}
}
}
}
}
class Read{
StringTokenizer st = new StringTokenizer("");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String next() throws IOException{
while(!st.hasMoreTokens()){
st = new StringTokenizer(br.readLine());
}
return st.nextToken();
}
int nextInt() throws IOException{
return Integer.parseInt(next());
}
long nextLong() throws IOException{
return Long.parseLong(next());
}
double nextDouble() throws IOException{
return Double.parseDouble(next());
}
}
E:爆破

这题考察的应该是最小生成树...俺不会,写的dijkstra,运气好的话希望能骗个一两分吧...
F:数组翻转(AC)

++数据范围++:

我们先考虑++暴力解法++:
其实就是将所有可能的翻转都尝试一遍,这样就能找到所有的情况,并且找出最大的。
但翻转这个操作本身就是O(n)的 ,再加上尝试所有范围翻转,就达到了O(n^3),这是非常可怕的
(即使如此也能暴力掉20%,也就是3分,接近一道填空题的分数了~)
但实际上,我们并不需要进行"翻转"这个操作,因为:
翻转数组的目的是:得到可通过拼接得到的最长目标值。
而我们再想一下,如何能知道"可拼接得到的最长目标值串"呢?其实,就是找到整个数组中,"等于目标值的最长子串"和"等于目标值的第二长子串"进行拼接即可。
如何证明?其实很好想,不管如何选取范围翻转,我们都没法改变范围内数组的本质顺序,也就是说,我们只能"选取部分进行拼接",而每次拼接,肯定只能选到两个子串拼接,如果想选三个,那么势必会有两个子串中有间隔。
所以,我们只需要找到"每个值对应数组中的第一长与第二长子串",将长度相加后,进行求分数即可,最后找到"子串拼接后分数最高的值",输出即可。
java
import java.util.*;
import java.io.*;
public class Main {
public static PrintWriter pr = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
public static Read in = new Read();
public static void main(String[] args) throws IOException{
int n = in.nextInt();
int[] arr = new int[n + 1];
HashSet<Integer> set = new HashSet<>();
for(int i = 1;i <= n;i++){
arr[i] = in.nextInt();
set.add(arr[i]);
}
arr[0] = Integer.MAX_VALUE;
HashMap<Integer,Integer> map1 = new HashMap<>();
HashMap<Integer,int[]> map2 = new HashMap<>();
int l = 1;
int r = 1;
while(r <= n){
int len = map1.getOrDefault(arr[l],0);
int newlen = 0;
while(r <= n && arr[l] == arr[r]){
newlen++;
r++;
}
if(len < newlen){
len = newlen;
map1.put(arr[l],len);
map2.put(arr[l],new int[]{l,r});
}
l = r;
}
HashMap<Integer,Integer> map3 = new HashMap<>();
l = r = 1;
//再次进行查找数组中的[第二长子串],跳过第一长子串即可
while(r <= n){
//为val = arr[l]的最长字串
if(map2.get(arr[l])[0] == l){
l = map2.get(arr[l])[1];
r = l;
continue;
}
int len = map3.getOrDefault(arr[l],0);
int newlen = 0;
while(r <= n && arr[l] == arr[r]){
newlen++;
r++;
}
if(len < newlen){
len = newlen;
map3.put(arr[l],len);
}
l = r;
}
long max = 0;
for(int a:set){
//有可能不存在第二长子串
int len = map1.get(a) + map3.getOrDefault(a,0);
long num = len * 1l * a;
max = Math.max(max,num);
}
System.out.println(max);
}
}
class Read{
StringTokenizer st = new StringTokenizer("");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String next() throws IOException{
while(!st.hasMoreTokens()) {
st = new StringTokenizer(br.readLine());
}
return st.nextToken();
}
String nextLine() throws IOException{
return br.readLine();
}
int nextInt() throws IOException{
return Integer.parseInt(next());
}
long nextLong() throws IOException{
return Long.parseLong(next());
}
double nextDouble() throws IOException{
return Double.parseDouble(next());
}
}
G:2的幂

这题不会...but!

所以我写的时候,先判断原数组是不是已经满足条件了,如果满足直接输出0,不满足直接输出-1...不知道能不能骗到分。
H:研发资源分配

范围:

不会...只会用全排列暴力骗分。
总的来说,感觉今年蓝桥杯的数学和贪心含量太高了...考前学了一堆算法,dijkstra,floyd,并查集,最近公共祖先...一个都没出呀,这就算了...二分,bfs,dfs都没出。有种学了半年砌砖,最后考我电焊的感觉.难受