Acwing4993. FEB

题目

有一个长度为 N 的字符串 S,其中的每个字符要么是 B,要么是 E

我们规定 S 的价值等于其中包含的子串 BB 以及子串 EE 的数量之和。

例如,BBBEEE 中包含 22 个 BB 以及 22 个 EE,所以 BBBEEE 的价值等于 44。

我们想要计算 S 的价值,不幸的是,在我们得到 S 之前,约翰将其中的一些字符改为了 F

目前,我们只能看到改动后 的字符串 S,对于其中的每个 F,我们并不清楚它之前是 B 还是 E

请你计算,改动前的 S 有多少种可能的价值并将所有可能价值全部输出。

输入格式

第一行包含一个整数 N

第二行包含改动后的字符串 S

输出格式

第一行输出一个整数 K,表示改动前的 S 的可能价值的数量。

接下来 K 行,按照升序顺序,每行输出一个可能价值。

数据范围

1≤N≤2×10^5

输入样例1:
复制代码
4
BEEF
输出样例1:
复制代码
2
1
2
输入样例2:
复制代码
9
FEBFEBFEB
输出样例2:
复制代码
2
2
3
输入样例3:
复制代码
10
BFFFFFEBFE
输出样例3:
复制代码
3
2
4
6

思路与代码

这道题没有模板可以套,所以我们要分类讨论。如果全部都是F的话证明价值从0-n都可以。如果不是就更具体讨论了。具体讨论如下(这里的low地点和high高点分别是最小价值和最高价值):

  1. 寻找第一个和最后一个非F字符的位置:

    • 使用两个指针 lr,分别初始化为字符串的开头和结尾。
    • while 循环找到第一个非 'F' 的字符的位置,分别赋给 lr
  2. 计算低点:

    • 创建一个 StringBuilder 对象 str,将其初始化为输入字符串 s
    • lr 的范围内遍历字符串。
    • 如果当前字符是 'F',则将其修改为 'B' 或 'E',使得相邻字符不相同。
    • 如果当前字符与前一个字符相同(即 str.charAt(i) == str.charAt(i - 1)),则增加 low 计数。
  3. 计算高点:

    • lr 的范围内遍历字符串。
    • 如果当前字符是 'F',则将其修改为与前一个字符相同。
    • 如果当前字符与前一个字符相同(即 str.charAt(i) == str.charAt(i - 1)),则增加 high 计数。
  4. 计算结束的范围和步长:

    • 计算从 lr 之间的字符个数(即 ends = l + n - 1 - r)。
    • 如果 ends 大于 0,说明字符串在两端有一些 'F',需要计入 high 中,此时将 high 增加 ends,并将步长 d 设置为 1。
  5. 输出结果:

    • 计算 high - low 的结果除以步长 d,并加上 1,得到最终输出的范围。
    • lowhigh 按照步长 d 遍历,输出结果
java 复制代码
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取输入
        int n = scanner.nextInt();
        String s = scanner.next();

        if (s.equals(new String(new char[n]).replace('\0', 'F'))) {
            // 如果全是F,输出整个范围
            System.out.println(n);
            for (int i = 0; i < n; i++) {
                System.out.println(i);
            }
        } else {
            // 寻找第一个和最后一个非F字符的位置
            int l = 0, r = n - 1;
            while (s.charAt(l) == 'F') l++;
            while (s.charAt(r) == 'F') r--;

            int low = 0, high = 0;
            StringBuilder str = new StringBuilder(s);

            // 计算低点
            for (int i = l; i <= r; i++) {
                if (str.charAt(i) == 'F') {
                    if (str.charAt(i - 1) == 'B') str.setCharAt(i, 'E');
                    else str.setCharAt(i, 'B');
                }
                if (i > l && str.charAt(i) == str.charAt(i - 1)) low++;
            }

            // 重置字符串
            str = new StringBuilder(s);

            // 计算高点
            for (int i = l; i <= r; i++) {
                if (str.charAt(i) == 'F') str.setCharAt(i, str.charAt(i - 1));
                if (i > l && str.charAt(i) == str.charAt(i - 1)) high++;
            }

            // 计算结束的范围和步长
            int ends = l + n - 1 - r, d = 2;
            if (ends > 0) {
                high += ends;
                d = 1;
            }

            // 输出结果
            System.out.println((high - low) / d + 1);
            for (int i = low; i <= high; i += d)
                System.out.println(i);
        }
    }
}

接着我们结合第一个测试用例来理解这个代码

输入样例1:

复制代码
4
BEEF

输出样例1:

复制代码
2
1
2

结合用例理解

执行到这串代码的时候:

java 复制代码
while (s.charAt(l) == 'F') {  
    l++;  
}  
while (s.charAt(r) == 'F') {  
    r--;  
}

l还是0,r变为2

计算低点

  • 执行到计算低点的代码时候,当i=2时,进来low++,所以low=1

  • 然后执行到i=3时,因为已经把F替换为跟前面一个字符不同的字符,所以进不到low++的判断

计算高点

  • 当i=2时,进入到了high判断里,high++了,high=1

计算ends

  • 主要是为了计算左右两端的F个数,因为左右两端有多少个 'F' 的原因是我们希望每个 'F' 都能够独立地成为一个分组。在计算高点 high 时,我们希望每个 'F' 能够单独计数,因此需要考虑两端的 'F' 个数
  • 所以在这里计算出ends=1,然后d就被设置为1,步长为1,高点就再加上1

输出:

  • (high - low) / d + 1 的计算是为了确定最终输出的分组数量
  • 步长 d 表示每次增加的索引步长,保证了每个 'F' 只能被计数一次
相关推荐
guodingdingh1 小时前
软件开发工作问题总结0718
java·开发语言·数据库
咖啡八杯3 小时前
GoF设计模式——解释器模式
java·后端·spring·设计模式
GuWenyue3 小时前
传统Agent工具两大痛点!300行代码落地MCP跨语言工具,彻底解耦LLM与工具
前端·人工智能·算法
优橙教育3 小时前
5G网优培训 vs Java开发:转行选哪个?
java·开发语言·5g
糖果店的幽灵3 小时前
【DeepAgents 从入门到精通】Context Management 上下文管理
java·人工智能·后端·spring·中间件·langgraph·deepagents
我叫洋洋4 小时前
C ++ [ hello world ]
c语言·c++·算法
腻害兔5 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:字典、短信、邮件、通知——后台系统的“基础设施四件套“!
java·前端·vue.js·产品经理·ai编程
碎光拾影5 小时前
ARM交叉工具链各工具作用及IMX6ULL平台LED+蜂鸣器裸机程序实现
java·开发语言·数据库
奋发向前wcx5 小时前
y1,y2总复习笔记5 2026.7.19
数据结构·笔记·算法
Miao121316 小时前
微服务 API 测试实践:海外某民宿平台如何构建模式驱动测试基础设施
java·开发语言