一、引言
提到枚举,大家的第一印象可能都是Java亦或者是C++中的enum,如下:
enum 枚举类型名 {
常量1,
常量2,
...
常量n
};
但在算法竞赛中的 “枚举”,可不止这么简单。重点:算法中的枚举,是一种思想,而不是一种语法结构!( •̀ ω •́ )y
二、枚举算法基础
核心思想:将所有可能罗列出来,逐一检验每个解,是否符合条件。(又称暴力解法-BF解法)
定义:简单来说,就是把所有可能的解空间进行遍历,逐一检验每个可能解是否是问题的真正解。
三、练习
枚举题型,更多会在填空题中考察。
提示( •̀ ω •́ )✧:
至少要独立思考10min,若20min后仍无思路在看解析,收获会更大!
1、好数(蓝桥真题)(解析)
2、蓝 (解析)
3、兴趣小组(蓝桥真题)(解析)
4、单词分析(蓝桥真题)(解析)
5、约数个数(蓝桥真题)(解析)
6、相乘(蓝桥真题)(解析)
7、直线(蓝桥真题)(解析)
8、大衣最多1的个数(解析)
拓展题型:
1、不高兴的津津(蓝桥真题)(解析)
2、特别数的和(蓝桥真题)(解析)
3、纯质数(蓝桥真题)(解析)
4、k倍区间(蓝桥真题)(解析)
目录
一、入门:
1、好数(蓝桥真题)
2、蓝
3、兴趣小组(蓝桥真题)
二、基础:
4、单词分析(蓝桥真题)
5、约数个数(蓝桥真题)
6、相乘(蓝桥真题)
三、进阶:
7、直线(蓝桥真题)
8、大衣最多1的个数
一、入门:
1、好数(蓝桥真题)
(枚举思想,将所有可能枚举出来)
问题描述
一个整数如果按从低位到高位的顺序,奇数位 (个位、百位、万位 ⋯⋯ ) 上的数字是奇数,偶数位 (十位、千位、十万位 ⋯⋯ ) 上的数字是偶数,我们就称之为 “好数”。
给定一个正整数 NN,请计算从 1 到 NN 一共有多少个好数。
输入格式
一个整数 NN。
输出格式
一个整数代表答案。
样例输入
24
样例输出
7
样例说明
对于第一个样例,2424 以内的好数有 11、33、55、77、99、2121、2323,一共 77 个。
评测用例规模与约定
对于 10%10% 的评测用例,1≤N≤1001≤N≤100 。
对于 100%100% 的评测用例,1≤N≤1071≤N≤107 。
Java版:
import java.util.Scanner; // 导入Scanner类,用于从控制台读取输入
public class Main {
// 定义一个方法来判断一个数字是否是“好数字”
public static boolean isGoodNum(int num) {
boolean flag = true; // 初始化标志位为true,假设当前数字是“好数字”
String str = Integer.toString(num); // 将整数num转换为字符串形式,便于逐位处理
// 从字符串的最后一位开始向前遍历
for (int i = str.length() - 1; i >= 0; --i) {
int number = str.charAt(i) - '0'; // 获取该位置的数字(字符转整数)
int place = str.length() - i; // 计算该数字在原数字中的位置(从1开始计数)
if (place % 2 == 0) { // 如果该位置是偶数位
if (number % 2 != 0) { // 如果该位置上的数字是奇数
flag = false; // 标记为非“好数字”
break; // 结束循环
}
} else { // 如果该位置是奇数位
if (number % 2 == 0) { // 如果该位置上的数字是偶数
flag = false; // 标记为非“好数字”
break; // 结束循环
}
}
}
return flag; // 返回标志位,表示是否是“好数字”
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in); // 创建一个Scanner对象,用于读取输入
int N = scanner.nextInt(); // 读取用户输入的整数N
int goodNumCount = 0; // 初始化计数器,记录“好数字”的数量
// 遍历从1到N的所有整数
for (int i = 1; i <= N; ++i) {
if (isGoodNum(i)) { // 调用isGoodNum方法检查当前数字是否为“好数字”
goodNumCount++; // 如果是,则计数器加1
}
}
System.out.println(goodNumCount); // 输出“好数字”的总数
scanner.close(); // 关闭scanner对象,防止资源泄露
}
}
C++版:
#include
using namespace std;
bool is_GoodNum(int num){
bool flag = true;
string str = to_string(num);
for(int i=str.size()-1; i>=0; --i){
int number = str[i]-'0'; // 获取该位置的数字
int place = str.size()-i; // 用数组代表,个位、十位、百位...
if(place%2==0){ // 偶数位
if(number%2!=0){
flag = false;
break;
}
} else { // 奇数位
if(number%2==0){ // 奇数位若是偶数,则错误
flag = false;
break;
}
}
}
return flag;
}
int main()
{
int N;
cin>>N;
int GoodNum = 0;
for(int i=1; i<=N; ++i){
if(is_GoodNum(i)) GoodNum++;
}
cout< return 0; } 2、蓝 本题有两点需注意, 1、类型大小要开到long(C++是 long long),int只能表示( -2,147,483,648 - 2,147,483,647之间的数字,大致就是:1的9次方左右,两亿。 超出范围,就会报错,就需要用long来储存。 ) 且C++版中 num += (long long)vec[i] * vec[j] * vec[k]; 与 num += (long long)(vec[i] * vec[j] * vec[k];) 是不一样的。 第二者,是错的 2、本题可用递归解决,但介于在练习枚举,便无伤大雅。 (额外,C++的switch要牢记语法框架) 问题描述 小蓝打算去参加蓝桥杯,他看到 lanqiao 这个英文,于是想到了一个问题。 现在有 nn 个小写英文单词,每个单词长度 1≤∣Si∣≤101≤∣Si∣≤10,他想从这些字符串中选出 33 个单词,要求这三个单词的首字符分别是 l,q,i,a,o 55 个字母中的一个,且首字母不能有重复。 现在小蓝想知道有多少种选择单词的方案,你可以写一个程序帮助他吗? 输入格式 第一行输入一个 nn ,表示输入的字符串的数量。 第二行输入 nn 个由空格隔开的小写英文单词 SiSi。 输出格式 输出一个整数,表示小蓝可以选择单词的方案数。 样例输入 5 lan qiao bei operation qqq 样例输出 2 说明 我们可以选择:lan,qiao,operation 与 lan,qqq,operation。 但是我们不能选择:qqq,qiao,lan,因为 q 字母重复了。 Java版: import java.util.Scanner; // 1:无需package // 2: 类名必须Main, 不可修改 public class Main { public static void main(String[] args) { Scanner scan = new Scanner(System.in); //在此输入您的代码... long n=scan.nextLong(); long[] arr={0,0,0,0,0}; while(n-- > 0){ String str=scan.next(); if(str.charAt(0)=='l') arr[0]++; else if(str.charAt(0)=='q') arr[1]++; else if(str.charAt(0)=='i') arr[2]++; else if(str.charAt(0)=='a') arr[3]++; else if(str.charAt(0)=='o') arr[4]++; } // 初始化一个长整型变量 sum,用于存储从以 'l'、'q'、'i'、'a'、'o' 开头的单词中选取 3 种不同开头的单词组合的总数 long sum = 0; // 使用三层嵌套的 for 循环来枚举所有可能的 3 种不同开头的单词组合 // 外层循环控制第一个索引 i,范围是从 0 到 2(因为要保证后续有两个不同的索引) for (int i = 0; i < 3; i++) { // 中层循环控制第二个索引 j,范围是从 i + 1 到 3,确保 j 大于 i for (int j = i + 1; j < 4; j++) { // 内层循环控制第三个索引 k,范围是从 j + 1 到 4,确保 k 大于 j for (int k = j + 1; k < 5; k++) { // 计算当前这 3 种开头的单词组合的数量,通过将对应数组元素相乘得到 // 并将结果累加到 sum 中 sum += arr[i] * arr[j] * arr[k]; } } } // 输出最终计算得到的组合总数 System.out.println(sum); // 关闭 Scanner 对象,释放相关资源,避免资源泄漏 scan.close(); } } C++版: #include #include using namespace std; int main() { // 本题是枚举类型,所以只需要记录每个字母开头,有几个单词就够了 int t; cin >> t; string str; vector while (t--) { cin >> str; // 根据单词的首字母,更新对应的计数 switch (str[0]) { case 'l': vec[0]++; break; case 'q': vec[1]++; break; case 'i': vec[2]++; break; case 'a': vec[3]++; break; case 'o': vec[4]++; break; default: // 若输入的单词不是以 'l', 'q', 'i', 'a', 'o' 开头,则跳过该单词 continue; } } long long num = 0; // 用3层循环,把所有可能枚举出来 // 其实还能用递归代替,但是现在是在讲解简单枚举,所以不用复杂方法 for (int i = 0; i < 3; ++i) { for (int j = i + 1; j < 4; ++j) { for (int k = j + 1; k < 5; ++k) { num += (long long)vec[i] * vec[j] * vec[k]; } } } cout << num << endl; return 0; } 3、兴趣小组(蓝桥真题) Java版: public class Main { // 定义一个公共类 Main,Java 程序执行时需要一个包含 main 方法的公共类作为入口 public static void main(String[] args) { // 定义一个整型数组 resA,用于存储一组整数数据 // 这里只是示例,实际使用时省略号 ... 应替换为完整的数据 int[] resA = {12894792, 92774113, 59529208, 22962224 ... }; // 定义一个整型数组 resB,同样用于存储一组整数数据 // 省略号 ... 需替换为完整的数据 int[] resB = {44894050, 34662733, 44141729, 92774113 ... }; // 定义一个整型数组 resC,存储另一组整数数据 // 省略号 ... 要替换为完整的数据 int[] resC = {13404901, 39952424, 47847739, 94939581 ... }; // 定义一个整型变量 num,初始化为 0,用于统计满足特定条件的元素个数 int num = 0; // 使用增强 for 循环遍历 resA 数组 // 每次循环,变量 i 依次取 resA 数组中的每个元素 for (int i : resA) { // 定义一个布尔型变量 flag,初始化为 false // 该变量用于标记当前元素 i 是否满足存在于 resB 且不存在于 resC 的条件 boolean flag = false; // 使用增强 for 循环遍历 resB 数组 // 每次循环,变量 j 依次取 resB 数组中的每个元素 for (int j : resB) { // 比较当前 resA 中的元素 i 和 resB 中的元素 j 是否相等 if (i == j) { // 如果相等,将 flag 置为 true,表示 i 在 resB 中被找到了 flag = true; } // 使用增强 for 循环遍历 resC 数组 // 每次循环,变量 k 依次取 resC 数组中的每个元素 for (int k : resC) { // 比较当前 resA 中的元素 i 和 resC 中的元素 k 是否相等 if (i == k) { // 如果相等,将 flag 置为 false,表示 i 存在于 resC 中,不满足条件 flag = false; } } } // 判断 flag 的值 if (flag) { // 如果 flag 为 true,说明元素 i 存在于 resB 且不存在于 resC // 满足条件,将计数器 num 加 1 num++; } } // 使用 System.out.println 方法输出满足条件的元素个数 num System.out.println(num); } } C++版: #include #include using namespace std; int main() { vector vector vector int num = 0; for(int i : resA){ bool flag = false; for(int j : resB){ if(i==j) flag=true; for(int k : resC){ if(i==k) flag=false; } } if(flag) num++; } cout< return 0; } 二、基础: 4、单词分析(蓝桥真题) Java版: import java.util.Scanner; public class Main { public static void main(String[] args) { // 创建一个大小为 26 的整型数组,用于统计每个字母的出现次数,初始值都为 0 int[] arr = new int[26]; // 创建一个 Scanner 对象,用于从标准输入读取用户输入的字符串 Scanner scanner = new Scanner(System.in); // 读取用户输入的一行字符串 String str = scanner.nextLine(); // 关闭 Scanner 对象,释放资源 scanner.close(); // 遍历字符串中的每个字符 for (char c : str.toCharArray()) { // 计算当前字符相对于 'a' 的偏移量,作为数组的索引 int num = c - 'a'; // 对应索引位置的计数加 1 arr[num]++; } // 初始化字母为 'a' char letter = 'a'; // 初始化最大出现次数为 -1 int letterNum = -1; // 遍历数组,找出出现次数最多的字母 for (int i = 0; i < 26; i++) { // 如果当前字母的出现次数大于之前记录的最大次数 if (letterNum < arr[i]) { // 更新最大出现次数 letterNum = arr[i]; // 根据索引计算对应的字母 letter = (char) (i + 'a'); } } // 输出出现次数最多的字母 System.out.println(letter); // 输出该字母的出现次数 System.out.println(letterNum); } } C++版: #include using namespace std; int main() { // 谈论到字典,能用26个英语字母表示 // 也能用map表示 int arr[26]{0}; string str; cin>>str; for(char c : str){ int num = c-'a'; arr[num]++; } char letter = 'a'; int letterNum = -1;; for(int i=0; i<26; ++i){ if(letterNum letterNum = arr[i]; letter = i+'a'; } } cout< cout< return 0; } 5、约数个数(蓝桥真题) 首先了解一下:什么是约数 # 小学数学 // 这道题目难就难在你不知道,啥是约数!然后没了 // 其他就是枚举(遍历所有可能),判断一下。 Java版: public class Main { public static void main(String[] args) { // 初始化变量number,用于记录1200000的约数个数,初始值为0 int number = 0; // 使用for循环进行枚举,从1到1200000 for (int i = 1; i <= 1200000; ++i) { // 判断i是否为1200000的约数,如果1200000除以i的余数为0,则i是1200000的约数 if (1200000 % i == 0) { // 如果i是约数,将number的值加1 number++; } } // 输出1200000的约数个数 System.out.println(number); } } C++版: #include using namespace std; // 这道题目难就难在你不知道,啥是约数!然后没了 // 其他就是枚举(遍历所有可能),判断一下。 int main() { int number = 0; for(int i=1; i<=1200000; ++i){ if(1200000%i==0) number++; } cout< return 0; } 6、相乘(蓝桥真题) 其实本题超级超级简单,这种题型也说明了为啥蓝桥杯,被称为暴力杯。 C++做这道题时不用担心超时。但是Java一定!要在循环结束后➕break,否则必然超时! Java版: import java.util.Scanner; public class Main { public static void main(String[] args) { // 定义一个长整型变量 flag,用于存储最终符合条件的 i 值,初始化为 0 long flag = 0; // 开始循环,从 1 到 1000000007 进行遍历 for (long i = 1; i <= 1000000007; i++) { // 计算 i 乘以 2021 之后对 1000000007 取模的结果,存储在 num 中 long num = (i * 2021) % 1000000007; // 判断 num 对 1000000007 取模的结果是否等于 999999999 if (num % 1000000007 == 999999999) { // 如果满足条件,将当前的 i 值赋给 flag flag = i; break; } } // 输出最终找到的符合条件的 i 值 System.out.println(flag); } } C++版: #include #define ll long long using namespace std; int main() { ll flag = 0; for(ll i=1; i<=1000000007; ++i){ ll num = i*2021%1000000007; if(num%1000000007 == 999999999) flag = i; } cout< return 0; } 三、进阶: 其实说是进阶,更不如说是综合题目,将多种知识糅合在一起,形成题目。 7、直线(蓝桥真题) Java不懂HashSet的点击这里 这道题目就是典型的,嘴上说着超级超级难,其实超级简单! 因为他就是一道(枚举+数学题型) 为啥呢?看完这个公式就知道了:y=mx+C 另大家感到难受无非两个点。 1、怎么把所有直线表示出来。 2、怎么判断表示出来的直线,是否重复! 第一条,挺好解决的,就是个枚举问题,答案大家肯定能看懂。 第二条,更容易解决,判断他的斜率是否相等就行。 m相等,证明两条直线平行或重合。C相等,证明两条直线相交。 题目描述 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。 在平面直角坐标系中,两点可以确定一条直线。如果有多点在一条直线上, 那么这些点中任意两点确定的直线是同一条。 给定平面上 2 × 3 个整点(x,y)∣0≤x<2,0≤y<3,x∈Z,y∈Z(x,y)∣0≤x<2,0≤y<3,x∈Z,y∈Z,即横坐标 是 00 到 11 (包含 0 和 1) 之间的整数、纵坐标是 0 到 2 (包含 0 和 2) 之间的整数 的点。这些点一共确定了 11 条不同的直线。 给定平面上 20×2120×21 个整点 (x,y)∣0≤x<20,0≤y<21,x∈Z,y∈Z(x,y)∣0≤x<20,0≤y<21,x∈Z,y∈Z,即横 坐标是 00 到 1919 (包含 00 和 1919) 之间的整数、纵坐标是 00 到 2020 (包含 00 和 2020) 之 间的整数的点。 请问这些点一共确定了多少条不同的直线。 Java题解 import java.util.HashSet; import java.util.Set; public class Main { /* 0<=x<20 0<=y<21 这些点确定了多少直线 提示: 0<=x<2 0<=y<3 这些点确定了11条直线 对于 y=ax+b, */ public static void main(String[] args) { Set //遍历x1,x2,y1,y2四个点 for (int x1 = 0; x1 < 20; x1++) { for (int y1= 0; y1 <21; y1++) { for(int x2 =0;x2<20;x2++) { for (int y2= 0; y2 <21; y2++) { set.add(fun(x1,y1,x2,y2)); } } } } System.out.println(set.size()-1); //去掉下面第一种情况 } private static String fun(int x1, int y1, int x2, int y2) { //虽然set支持去重(方程一样),但是对于下面的三种情况,无法去重。 if(x1==x2&&y1==y2) { return "_"; } else if(x1==x2) { return "x="+x1; // 垂直于 x 轴 } else if(y1==y2) { return "y="+y1;// 垂直于 y 轴 }else { double k =(y2-y1)*1.0 /(x2-x1); double b = (y1*x2 - y2*x1)*1.0/(x2-x1); b+=0.0; //注意,这里必须加这一步,因为上一步的计算并不会改变b变量本身的数据类型 return "y="+k+"x+"+b; //交给set存储 } } } C++题解 #include #include using namespace std; // 在做这种题目时,为避免精度问题,尽量将公式展开 // 接下来,两行其实是等价的,都是由一个公式推导出来的,但是第一个是错的! // double c = (double)(y0-k*x0); // double c = (double)(x0*y1-x1*y0)/(x0-x1); // 因为,第一个,减少了中间步骤,也就减少了浮点数精度误差累积的机会,所以在某些情况下可能会得到更准确的结果。 int main() { set for(int x0=0; x0<20; ++x0){ for(int x1=0; x1<20; ++x1){ for(int y0=0; y0<21; ++y0){ for(int y1=0; y1<21; ++y1){ if(x1==x0&&y1==y0) continue; // 两点相同的情况 if(x1==x0) continue; // 垂直时,跳过,后面加上20 // 分析垂直情况 double k = (double)(y0-y1)/(x0-x1); // double c = (double)(y0-k*x0); double c = (double)(x0*y1-x1*y0)/(x0-x1); s1.insert({k,c}); } } } } cout< return 0; } 8、大衣最多1的个数 不了解⊕符号的,请点击下方!!! 了解符号异或( ^ 也就是本题中的 ⊕) 问题描述 大衣有一个长度为 NN 的二进制字符串 SS。 你需要构造一个长度为 NN 的字符串 XX: 对于每一个索引 i(1≤i≤N)i(1≤i≤N),有 X(i+1)=Xi⊕SiX(i+1)=Xi⊕Si,其中 ⊕⊕ 表示按位异或。字符串 XX 中字符 11 的个数最多。 请找出字符串 XX 中 11 的最多个数。 输入格式 第一行输入一个正整数 TT 表示测试数据的组数。 接下来 TT 组测试数据每组输入两行: 第一行输入一个正整数 NN 表示字符串 SS 的长度。 第二行输入一个长度为 NN 个二进制字符串 SS。 输出格式 对于每组测试数据,输出一个整数表示字符串 XX 中 11 的最多个数,并换行。 样例输入1 3 4 0011 4 1100 4 1010 样例输出1 3 3 2 说明 样例 11:考虑字符串 X=1110X=1110,其中 X2=X1⊕S1=1⊕0,X3=X2⊕S2=1⊕0,X4=X3⊕S3=1⊕1X2=X1⊕S1=1⊕0,X3=X2⊕S2=1⊕0,X4=X3⊕S3=1⊕1,字符串包含 33 个 11,可以证明没有更多的构造方案。 样例 22:考虑字符串 X=1011X=1011,其中 X2=X1⊕S1=1⊕1,X3=X2⊕S2=0⊕1,X4=X3⊕S3=1⊕0X2=X1⊕S1=1⊕1,X3=X2⊕S2=0⊕1,X4=X3⊕S3=1⊕0,字符串包含 33 个 11,可以证明没有更多的构造方案。 样例 33:考虑字符串 X=0110X=0110,字符串包含 22 个 11,可以证明没有更多的构造方案。 java版 import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); // 读取测试用例的数量 int t = scanner.nextInt(); while (t > 0) { // 读取字符串的长度 int N = scanner.nextInt(); // 读取字符串 String str = scanner.next(); // 用于记录初始值为 0 和 1 时 1 的个数 int num0 = 0; int num1 = 0; // 初始化 X0 为 0,X1 为 1 int X0 = 0; int X1 = 1; // 遍历字符串 for (int i = 0; i < N; i++) { // 将字符转换为整数 int S = str.charAt(i) - '0'; // 假设 X 初始为 0 if (X0 == 1) { num0++; } // 假设 X 初始化为 1 if (X1 == 1) { num1++; } // 更新 X0 和 X1 的值 X0 = X0 ^ S; X1 = X1 ^ S; } // 输出 num0 和 num1 中的最大值 System.out.println(Math.max(num0, num1)); t--; } scanner.close(); } } C++版 #include using namespace std; // 其实不难,别被题目|゚Д゚)))吓到 // 本质就俩, // 1、理解异或运算符 // 2、知道这是一个递推公式,只需要把X0初始化1或0就行。 int main() { // 这道题目很简单,只是会害怕与字符串 int t; cin>>t; while(t--){ int N; cin>>N; string str = ""; // 初始化 cin>>str; // 输入字符串 int num0 = 0; // 用于记录1的个数 int num1 = 0; int X0 = 0; int X1 = 1; for(int i=0; i int S = str[i]-'0'; // 假设X初始为0 if(X0==1) num0++; // 假设X初始化为1 if(X1==1) num1++; X0 = X0^S; X1 = X1^S; } cout< } return 0; } 四、拓展: (由学习部强烈推荐) 1、不高兴的津津(蓝桥真题) (由学习部推荐,并挑选答案) 题目描述 津津上初中了。妈妈认为津津应该更加用功学习,所以津津除了上学之外,还要参加妈妈为她报名的各科复习班。另外每周妈妈还会送她去学习朗诵、舞蹈和钢琴。但是津津如果一天上课超过八个小时就会不高兴,而且上得越久就会越不高兴。假设津津不会因为其它事不高兴,并且她的不高兴不会持续到第二天。请你帮忙检查一下津津下周的日程安排,看看下周她会不会不高兴;如果会的话,哪天最不高兴。 输入描述 输入七行数据,分别表示周一到周日的日程安排。每行包括两个小于 1010 的非负整数,用空格隔开,分别表示津津在学校上课的时间和妈妈安排她上课的时间。 输出描述 输出一个数字。如果不会不高兴则输出 00,如果会则输出最不高兴的是周几(用 1,2,3,4,5,6,71,2,3,4,5,6,7 分别表示周一,周二,周三,周四,周五,周六,周日)。如果有两天或两天以上不高兴的程度相当,则输出时间最靠前的一天。 输入输出样例 示例 1 输入 5 3 6 2 7 2 5 3 5 4 0 4 0 6 输出 3 Java版 import java.util.Scanner; public class 不高兴的津津 { public static void main(String[] args) { Scanner scan=new Scanner(System.in); //创建3个数字arr1表示上课,arr2表示补课,sum表示一天心情 int[]arr1=new int[7]; int[]arr2=new int[7]; int[]sum=new int[7]; for (int i = 0; i <7; i++) { arr1[i]= scan.nextInt(); arr2[i]= scan.nextInt(); sum[i]=arr1[i]+arr2[i]; } int max=0; int n=0; //找出最大值,并用n来标记 for (int i = 0; i <7; i++) { if (sum[i]>max){ max=sum[i]; n=i; } } //判断最大值是否满足开不开心的条件 if (max<=8){ System.out.println(0); }else System.out.println(n+1); } } 2、特别数的和(蓝桥真题) (由学习部推荐,并挑选答案) 题目描述 小明对数位中含有 2、0、1、9 的数字很感兴趣(不包括前导 0),在 1 到 40 中这样的数包括 1、2、9、10 至 32、39 和 40,共 28 个,他们的和是 574。 请问,在 1 到 nn 中,所有这样的数的和是多少? 输入描述 输入格式: 输入一行包含两个整数 n(1≤n≤104)n(1≤n≤104)。 输出描述 输出一行,包含一个整数,表示满足条件的数的和。 输入输出样例 示例 输入 40 输出 574 Java版 import java.util.Scanner; public class 特别数的和 { public static void main(String[] args) { Scanner scan = new Scanner(System.in); int n = scan.nextInt(); //sum要用long类型 long sum = 0; for (int i = 1; i <= n; i++) { //将每个数都转换为字符串类型,再用contains方法进行检测 String s = String.valueOf(i); if (s.contains("2") || s.contains("0") || s.contains("1") || s.contains("9")) { //检测到之后转换为long类型,进行求和 long l = Long.parseLong(s); sum += l; } } System.out.println(sum); } } 3、纯质数(蓝桥真题) (由学习部推荐,并挑选答案) 题目描述 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。 如果一个正整数只有 11 和它本身两个约数,则称为一个质数(又称素数)。 前几个质数是:2,3,5,7,11,13,17,19,23,29,31,37,⋅⋅⋅2,3,5,7,11,13,17,19,23,29,31,37,⋅⋅⋅ 。 如果一个质数的所有十进制数位都是质数,我们称它为纯质数。例如:2,3,5,7,23,372,3,5,7,23,37 都是纯质数,而 11,13,17,19,29,3111,13,17,19,29,31 不是纯质数。当然 1,4,351,4,35 也不是纯质数。 请问,在 11 到 2021060520210605 中,有多少个纯质数? 运行限制 最大运行时间:1s最大运行内存: 256M Java版 import java.util.Scanner; public class 纯质数 { public static void main(String[] args) { Scanner scan=new Scanner(System.in); long sum=0; boolean b=false; for (int i = 2; i <=20210605; i++) { boolean q=false; //检验是否为质数 for (int j = 2; j <=Math.sqrt(i); j++) { if (i%j==0&&i!=j){ q=true; break; } } //如果不是质数会直接进入下一次循环 if (q){ continue; } //如果这个数为质数,开始对每一位进行质数检测 String s=String.valueOf(i); for (int j = 0; j int a=s.charAt(j)-48; b=false; if (a==0||a==1){b=true;} //进行质数检测 for (int k = 2; k <=Math.sqrt(a); k++) { if (a%k==0&&a!=k){ b=true; break; } } if (b){ break; } }//当所有位置全部都为质数,进行++,有一个位置不通过b就会变成false if (!b) { sum++; } } System.out.println(sum); } } 4、k倍区间(蓝桥真题) (由学习部推荐,并挑选答案) 题目描述 给定一个长度为 NN 的数列,A1,A2,⋯ANA1,A2,⋯AN,如果其中一段连续的子序列 Ai,Ai+1,⋯AjAi,Ai+1,⋯Aj ( i≤ji≤j ) 之和是 KK 的倍数,我们就称这个区间 [i,j][i,j] 是 K 倍区间。 你能求出数列中总共有多少个 KK 倍区间吗? 输入描述 第一行包含两个整数 NN 和 KK( 1≤N,K≤1051≤N,K≤105 )。 以下 N 行每行包含一个整数 AiAi ( 1≤Ai≤1051≤Ai≤105 ) 输出描述 输出一个整数,代表 K 倍区间的数目。 输入输出样例 示例 输入 5 2 1 2 3 4 5 输出 6 Java版 import java.util.Scanner; // 1:无需package // 2: 类名必须Main, 不可修改 public class k倍区间 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int k = sc.nextInt(); long sum = 0; long[] mod = new long[k]; for(int i=0;i sum += sc.nextLong(); // 利用求余数 将相同余数的元素放到一起 mod[(int)(sum%k)]++; } // 余数为0的元素自成一个 k倍区间 long res = mod[0]; for(int i=0;i // 两个相同余数的元素。他们的差一定为 k倍区间, 13%2=1 25%2=1 (25-13)%2==0 // 任意两个数都可以组合一次 相当于 c(2,x) = x(x-1)/2 res += (mod[i]*(mod[i]-1))/2; } System.out.println(res); } } (切记,自己先实践,仍然无头绪,在询问组长) 借鉴博客、视频、网站: 1、蓝桥杯官网 2、什么是约数 # 小学数学 3、Java不懂HashSet的点击这里 4、了解符号异或( ^ 也就是本题中的 ⊕) ( •̀ ω •́ )✧点击这里,继续学习其他模块吧!