FEB

发布时间 2024-01-09 21:24:05作者: zhyyyyy115

题目描述

有一个长度为 N的字符串 S,其中的每个字符要么是 B,要么是 E。
我们规定 S的价值等于其中包含的子串 BB 以及子串 EE 的数量之和。
例如,BBBEEE 中包含 2个 BB 以及 2个 EE,所以 BBBEEE 的价值等于 4。
我们想要计算 S的价值,不幸的是,在我们得到 S之前,约翰将其中的一些字符改为了 F。
目前,我们只能看到改动后的字符串 S,对于其中的每个 F,我们并不清楚它之前是 B 还是E
请你计算,改动前的 S 有多少种可能的价值并将所有可能价值全部输出。

输入格式

第一行包含一个整数 N。

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

输出格式

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

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

数据范围

\(1 \le N \le 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

题解

我们将本题的B、E改写为0,1,F为x,方便后面讨论

分段考虑这道题目,变化在于x的变化

分4种情况
第1种情况,xxxxxxx(k)情况的可能取值:k-1, k-2, k-3,..., 0; min = 0,max = k-1; d = 1;
第2种情况,0xxxxxx(k)情况的可能取值:k, k-1, k-2,..., 0; min = 0, max = k; d = 1;
第3种情况,0xxxxx0(k)情况的可能取值:k为奇数:k+1, k-1, k-3,..., 0; min = 0, max = k+1; d = 2;
k为偶数:k+1, k-1, k-3,...,1; min = 1, max = k+1; d = 2
第4种情况,0xxxxx1(k)情况的可能取值:k为奇数:k, k-2, k-3,..., 1; min = 1, max = k; d = 2;
k为偶数:k, k-2, k-3,..., 0; min = 0, max = k; d = 2;

考虑如何合并公差为2的等差数列,两个数列合并后的结果是,min = min_a + min_b, max = max_a + max_b, 公差为2的等差数列
考虑如何合并公差为1的等差数列,两个数列合并后的结果是,min = min_a + min_b, max = max_a + max_b, 公差为1的等差数列
考虑如何合并公差为1和公差为2的等差数列,两个数列合并的结果是,min = min_a + min_b, max = max_a + max_b, 公差为1的等差数列

1.先特判情况1和n=1的情况
2.再算出中间段的情况3和4,合并公差为2等差数列
3.算两边的公差为1的情况
4.最终合并公差为1和2的情况

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define ppb pop_back
#define SZ(v) ((int)v.size())
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef double db;
using namespace std;
const int N = 1e6;
int _;

int n;
string s;
int ans;
int min_1, min_2, max_1, max_2;

void solve() {
    cin >> n >> s;
    if(n == 1) {
        cout << 0 << "\n";
        return;
    }
    // 情况1
    if(s == string(n, 'F')) {
        cout << n << "\n";
        for(int i = 0; i <= n - 1; i++) {
            cout << i << "\n";
        }
        return;
    }
    // 算固定值
    for(int i = 1; i < n; i++) {
        if(s[i] != 'F' && s[i-1] != 'F' && s[i] == s[i-1]) {
            ans++;
        }
    }
    // 算两边公差为1的值
    // 算左边为'F'的一段
    int sum = 0;
    for(int i = 0; i < n && s[i] == 'F'; i++) {
        sum++;
    }
    max_1 += sum;
    // 算右边为'F'的一段
    sum = 0;
    for(int i = n - 1; i >= 0 && s[i] == 'F'; i--) {
        sum++;
    }    
    max_1 += sum;
    // cout << max_1 << '\n';
    // 情况2,3,4
    int l = -1, r = -1;
    int k;
    for(int i = 0; i < n; i++) {
        if(s[i] == 'F') {
            if(l == -1) {
                l = r = i;
            }
        } else if(l != -1) {
            r = i - 1;
            k = (r - l + 1);
            // cout << "l = " << l << " " << "r = " << r << "\n";
            if(l != 0 && r + 1 != n) {
                if(s[l - 1] == s[r + 1]) {
                    if(k & 1) {
                        max_2 += k + 1;
                    } else {
                        min_2 += 1;
                        max_2 += k + 1;
                    }
                } else {
                    if(k & 1) {
                        min_2 += 1;
                        // cout << "min_2 = " << min_2 << "\n";
                        max_2 += k;
                    } else {
                        max_2 += k;
                    }
                }
            }
            l = -1;
        }
        
    }

    if(max_1 == 0) {
        cout << (max_2 - min_2 + 2) / 2 << "\n";
        for(int i = min_2; i <= max_2; i += 2) {
            cout << ans + i << "\n";
        }
        return;
    }
    min_1 += min_2;
    max_1 += max_2;
    cout << max_1 - min_1 + 1 << "\n";
    for(int i = min_1; i <= max_1; i++) {
        cout << ans + i << "\n";
    }
}   
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
    _ = 1;
    // cin >> _;
    while(_--) {
        solve();
    }
    return 0;
}