【无标题】

4993.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×105

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

二、题目分析

  • 时间复杂度

    • N = 2e5,在时间复杂度为**O(nlogn)**内
  • 样例模拟

    • 通过模拟样例,试图通过分类讨论对B,E,F进行处理,假设B=0, E=1, F=Xk表示x的数量
    • 情况一:xxxxxxxx:共有k种情况,0,1,2,3···,k-1 d = 1的等差数列
    • 情况二:0xxxxxxx:共有k+1种情况(同理于1xxxxxxx,xxxxxxx1,xxxxxxx0),0,1,2,3,···,k-1, d = 1的等差数列
    • 情况三:0xxxxxx0:k+1,k-1,k-3,k-5····· d=2的等差数列
    • 情况四:0xxxxxx1:
      • 当k为奇数时,举例k=5,0xxxxx1时,每一位与前一位取不同值时,有最小值min = 1,从k,k-2,···1的d=2的等差数列
      • 当k为偶数时,举例k=6,0xxxxxx1时,每一位与前一位取不同值时,有最小值min=0, 从k,k-2, ··· 0的d=2的等差数列
  • 等差数列合并

    • 合并两个d为2的等差数列,仍然会得到一个公差为2的等差数列
      • a1,a2,a3,··· an 与 b1,b2,b3 ··· bn,合并为a1+b1,···,a1+bn,b1+a1,···,b1 + an
    • 合并两个d分别为2和1的等差数列,可以取得an + bm,an + bm-1, an-1 + bm-1,···a1 + b1,d为1的等差数列
  • 方法步骤

    • 第一步,先求中间的段
    • 第二步,求两端的段
    • 如果第二步存在,d=1,否则d=2
#include<bits/stdc++.h>
using namespace std;


int main(){
    int n;
    string str;

    cin >> n >> str;
    if(str == string(n, 'F')){
        cout << n << endl;
        for(int i = 0; i < n; i ++)
            cout << i << endl;
    }

    else {
        int l = 0, r = n - 1;
        while(str[l] == 'F') l ++;
        while(str[r] == 'F') r --;
        
        int low = 0, high = 0;
        auto s = str;
        for(int i = l; i <= r; i ++){
            if(s[i] == 'F' ){
                if(s[i - 1] == 'B') s[i] = 'E';
                else s[i] = 'B';
            }
            if(i > l && s[i] == s[i - 1]) low ++; 
        }

        s = str;
        for(int i = l; i <= r; i ++){
            if(s[i] == 'F') s[i] = s[i - 1];
            if(i > l && s[i] == s[i - 1])   high ++;
        }

        int ends = l + n - 1 - r, d = 2;
        if(ends)    high += ends, d = 1;

        cout << (high - low) / d + 1 << endl;
        for(int i = low; i <= high; i += d)
            cout << i << endl;
    }
}

三、总结

本题重在分类讨论,核心是找到d=2和d=1的等差数列,没做出来的原因是未考虑到连续F对本题的作用。

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值