子串分值——第十一届蓝桥杯AC
题目描述
对于一个字符串 S,我们定义 S 的分值 f ( S ) 为 S 中恰好出现一次的字符个数。
例如 f ( “ a b a ” ) = 1 ,f ( “ a b c ” ) = 3
f(“aaa”)=0。
现在给定一个字符串 S [ 0… n − 1 ] ,请你计算对于所有 S 的非空子串 S [ i . . j ] S[i…j]S[i…j] ,f ( S [ i . . j ] ) f(S[i…j])f(S[i…j])
的和是多少。
输入格式:
输入一行包含一个由小写字母组成的字符串 S。
输出格式
输出一个整数表示答案。
输入样例
ababc
输出样例
21
思路
- 我们要求所有非空子串中出现次数为一的元素的和,也就是求基于字符串每一个元素达到出现一次的所有字符串之和;
- 用 pre[i] 记录第 i 个字母上一次出现的位置,那么往左最多能延伸到 pre[i] + 1,其到第 i 个字母一共有 i - pre[i] 个字母;
- 用 next[i] 记录第 i 个字母下一次出现的位置,同理往右最多能延伸到 next[i] - 1,其到第 i 个字母一共有 next[i] - i 个字母;
- 二者相乘,就是该字母出现一次的所有子串的数目;
代码
#include <iostream>
// memset 需要 cstring 头文件
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int pre[N], nex[N];
int idx[26];
int main() {
string s;
cin >> s;
s = " " + s;
ll res = 0;
int n = s.size();
for (int i = 1; i < n; ++i) {
pre[i] = idx[s[i] - 'a'];
idx[s[i] - 'a'] = i;
}
for (int i = 0; i < 26; ++i)
idx[i] = n;
for (int i = n - 1; i; --i) {
nex[i] = idx[s[i] - 'a'];
idx[s[i] - 'a'] = i;
}
for (int i = 1; i < n; ++i) {
res += (ll) (i - pre[i]) * (nex[i] - i);
}
cout << res;
return 0;
}
以下题目和该题相似,可以参考。欢迎大家批评指正
[蓝桥杯2020初赛] 子串分值和 题解 C++