枚举算法(竞赛必备)

一、引言

提到枚举,大家的第一印象可能都是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 vec(5, 0); // 标记每种单词依次+1

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 resA{ 12894792, 92774113, 59529208, 22962224 ... };

vector resB{ 44894050, 34662733, 44141729, 92774113 ... };

vector resC{ 13404901, 39952424, 47847739, 94939581 ... };

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 set= new HashSet<>();

//遍历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> s1;

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​,其中 ⊕⊕ 表示按位异或。字符串 X​X​ 中字符 1​1​ 的个数最多。

请找出字符串 XX 中 11 的最多个数。

输入格式

第一行输入一个正整数 T​T​ 表示测试数据的组数。

接下来 TT 组测试数据每组输入两行:

第一行输入一个正整数 NN 表示字符串 SS 的长度。

第二行输入一个长度为 NN 个二进制字符串 SS。

输出格式

对于每组测试数据,输出一个整数表示字符串 XX 中 1​1​ 的最多个数,并换行。

样例输入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,可以证明没有更多的构造方案。

样例 2​2​:考虑字符串 X=1011​X=1011​,其中 X2=X1⊕S1=1⊕1,X3=X2⊕S2=0⊕1,X4=X3⊕S3=1⊕0​X2​=X1​⊕S1​=1⊕1,X3​=X2​⊕S2​=0⊕1,X4​=X3​⊕S3​=1⊕0​,字符串包含 3​3​ 个 1​1​,可以证明没有更多的构造方案。

样例 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、了解符号异或( ^ 也就是本题中的 ⊕)

( •̀ ω •́ )✧点击这里,继续学习其他模块吧!