CF1083B Fair Nut和字符串

1 CF1083B Fair Nut和字符串

2 题目描述

最近,\(Fair Nut\) 写了 \(𝑘\) 个长度为 \(𝑛\) 的字符串,由字母 \(a\)\(b\) 组成。他计算了至少为一个给定字符串的前缀的字符串的个数 \(c\)
但是,他把写下来的纸给弄丢了。他记得所有写下来的字符串的字典序不小于字符串 \(𝑠\) 也不大于字符串 \(𝑡\)。他想知道 \(c\) 可能的最大值是多少。
只有当下面的某一条成立时字符串 \(a\) 的字典序比 \(b\) 小:

  • \(𝑎\)\(𝑏\) 的前缀,但 \(𝑎\)\(𝑏\)
  • \(𝑎\)\(𝑏\) 不同的最高的那一位上 \(a\) 小于 \(b\)

3 题解

我们可以考虑一位一位地去计算所有可能的 \(prefix\) 情况。我们考虑从前往后枚举字符串,这是因为前面的字符每修改一个,答案都会增加很多。当我们修改一个结尾时,我们最多只能增加一种情况,而当我们修改开头时,我们能增加 \(n\) 种情况。我们发现,我们每枚举一位,接下来的一位都有 \(2\) 种情况:\(a\)\(b\)。而如果这一位的上限等于这一位下限,说明我们多计算了一种情况,我们就将总情况数\(-1\)。这里解释一下为什么我们只用将答案 \(-1\):在枚举情况时,只有所有的字符都跟上限一样的那种情况受上限和下限的影响。其他情况在前面的某个字符肯定小于相应位的上限字符,导致这一位随便取 \(a\) 或者 \(b\) 都可以满足。而当上限的这一位为 \(a\),下限的这一位为 \(b\) 时,我们多计算了两种情况,所以我们将总情况数 \(-2\)。这里多减的 \(1\) 是对于之前所有位等于下限的情况中的 \(a\) 这一可能性。要注意的是:当总情况数超过 \(k\) 时,我们不计算新的情况数,之后的每一位都对答案加上 \(k\)

4 代码(空格警告):

#include <iostream>
using namespace std;
#define int long long
int n, k, ans, cnt;
string s, t;
bool flag;
signed main()
{
    cin >> n >> k;
    cin >> s >> t;
    cnt = 1;
    for (int i = 0; i < n; i++)
    {
        cnt *= 2;
        if (s[i] == 'b' && t[i] == 'b') cnt--;
        if (s[i] == 'a' && t[i] == 'a') cnt--;
        if (s[i] == 'b' && t[i] == 'a') cnt -= 2;
        if (cnt > k) flag = 1;
        if (flag) ans += k;
        else ans += cnt;
    }
    cout << ans;
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-02-05 16:05  David24  阅读(70)  评论(0编辑  收藏  举报