枚举算法(竞赛必备)

一、引言

提到枚举,大家的第一印象可能都是Java亦或者是C++中的enum,如下:

enum 枚举类型名 {
    常量1,
    常量2,
    ...
    常量n
};

但在算法竞赛中的 “枚举”,可不止这么简单。重点:算法中的枚举,是一种思想,而不是一种语法结构!( •̀ ω •́ )y

二、枚举算法基础

核心思想:将所有可能罗列出来,逐一检验每个解,是否符合条件。(又称暴力解法-BF解法)

定义:简单来说,就是把所有可能的解空间进行遍历,逐一检验每个可能解是否是问题的真正解。

三、练习

枚举题型,更多会在填空题中考察。

提示( •̀ ω •́ )✧

至少要独立思考10min,若20min后仍无思路在看解析,收获会更大!

1、好数(蓝桥真题)(解析)

2、蓝 (解析)

3、兴趣小组(蓝桥真题)(解析)

4、单词分析(蓝桥真题)(解析)

5、约数个数(蓝桥真题)(解析)

6、相乘(蓝桥真题)(解析)

7、直线(蓝桥真题)(解析)

8、大衣最多1的个数(解析)


目录

一、入门:

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 <iostream>
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<<GoodNum<<endl;
    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 个单词,要求这三个单词的首字符分别是 lqiao 55 个字母中的一个,且首字母不能有重复。

现在小蓝想知道有多少种选择单词的方案,你可以写一个程序帮助他吗?

输入格式

第一行输入一个 nn ,表示输入的字符串的数量。

第二行输入 nn 个由空格隔开的小写英文单词 SiSi​。

输出格式

输出一个整数,表示小蓝可以选择单词的方案数。

样例输入

5
lan qiao bei operation qqq

样例输出

2

说明

我们可以选择:lanqiaooperation 与 lanqqqoperation

但是我们不能选择:qqqqiaolan,因为 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 <iostream>
#include <vector>
using namespace std;

int main()
{
    // 本题是枚举类型,所以只需要记录每个字母开头,有几个单词就够了
    int t;
    cin >> t;
    string str;
    vector<int> 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 <iostream>
#include <vector>
using namespace std;
int main()
{
  vector<int> resA{ 12894792, 92774113, 59529208, 22962224 ... };
  vector<int> resB{ 44894050, 34662733, 44141729, 92774113 ... };
  vector<int> 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<<num<<endl;
  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 <iostream>
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<arr[i]){
            letterNum = arr[i];
            letter = i+'a';
        }
    }
    cout<<letter<<endl;
    cout<<letterNum<<endl;
    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 <iostream>
using namespace std;

// 这道题目难就难在你不知道,啥是约数!然后没了
// 其他就是枚举(遍历所有可能),判断一下。

int main()
{
  int number = 0;
  for(int i=1; i<=1200000; ++i){
    if(1200000%i==0) number++;
  }
  cout<<number<<endl;
  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 <iostream>
#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<<flag<<endl;
  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<String> 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 <iostream>
#include <set>
using namespace std;

// 在做这种题目时,为避免精度问题,尽量将公式展开
// 接下来,两行其实是等价的,都是由一个公式推导出来的,但是第一个是错的!
// double c = (double)(y0-k*x0);
// double c = (double)(x0*y1-x1*y0)/(x0-x1);
// 因为,第一个,减少了中间步骤,也就减少了浮点数精度误差累积的机会,所以在某些情况下可能会得到更准确的结果。

int main()
{
    set<pair<double,double>> 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<<s1.size()+20<<endl;

    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 <iostream>
    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<N; ++i){ // 必须要完整的遍历,最后一次遍历X0,X1也会改变,但是不会生效。
                int S = str[i]-'0';
                // 假设X初始为0
                if(X0==1) num0++;
                // 假设X初始化为1
                if(X1==1) num1++;
                X0 = X0^S;
                X1 = X1^S;
            }
            cout<<max(num0,num1)<<endl;
        }
        return 0;
    }

    (切记,自己先实践,仍然无头绪,在询问组长)


    借鉴博客、视频、网站

    1、蓝桥杯官网

    2、什么是约数 # 小学数学

    3、Java不懂HashSet的点击这里

    4、了解符号异或( ^ 也就是本题中的  ⊕)


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

    作者:ん贤

    物联沃分享整理
    物联沃-IOTWORD物联网 » 枚举算法(竞赛必备)

    发表回复