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;
}