问题描述
对于一个字符串 S,我们定义 S 的分值 f(S) 为 S 中出现的不同的字符个数。例如 f("aba")=2,f("abc")=3, f("aaa")=1。
现在给定一个字符串 S[0..n−1](长度为 n),请你计算对于所有 S 的非空子串 S[i..j](0≤i≤j<n),f(S[i..j])的和是多少。
输入格式
输入一行包含一个由小写字母组成的字符串 S。
输出格式
输出一个整数表示答案。
样例输入
ababc
样例输出
28
样例解释
子串 f值
a 1
ab 2
aba 2
abab 2
ababc 3
b 1
ba 2
bab 2
babc 3
a 1
ab 2
abc 3
b 1
bc 2
c 1
解题思路:
每个字母只有在第一次出现时才有贡献度,因此可以统计每个字母在第一次出现的情况下,能被多少子串所包含;
用 a[s[i]] 记录字母 s[i] 上一次出现的位置;
那么往左最多能延伸到 a[s[i]] + 1,其到第 i 个字母一共有 i - a[s[i]] 个字母;
同理往右最多能延伸到 n,其到第 i 个字母一共有 n - i + 1 个字母;
以样例 ababc 为例,求第 2 个 'a' 的贡献度
第一个 'a' 的下标为 1,第二个 'a' 的下标为 3;
所以向左最多延伸到 'b',即下标 2;向右最多能延伸到 'c',即下标 5;
因此 (3 - 1) * (5 - 3 + 1) = 6
第 2 个 'a' 能被以下 6 个子串所包含:
1、a 2、ab 3、abc 4、ba 5、bab 6、babc
二者相乘,就是该字母被不同子串所包含的总次数;
5 + 8 + 6 + 4 + 5 = 28
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int a[200];
int main()
{
string s;
cin >> s;
int n = s.size();
s = ' ' + s;//让字符串的下标从 1 开始,否则在算第一个字母时,就会出现 (0 - 0) * (n - 0 + 1) = 0 这种情况,但第一个字母是有 1 个贡献度的
LL ans = 0;
for (int i = 1; i <= n; i ++)
{
ans += (LL)(i - a[s[i]]) * (n - i + 1);
a[s[i]] = i;
}
cout << ans << "\n";
return 0;
}