题目描述
对于一个字符串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
对于所有评测用例,1 ≤ n ≤ 100000。
输出格式
输出一个整数表示答案。
输入样例
ababc
输出样例
28
分析
1、首先,我们将字符串的index从1开始计算,即1-n
2、其次,定义dp[i]:以s[i]字母结尾的答案,这样不仅可以无差漏的计算所有的字符串种类,还可以表示答案。
比如字符串 abab
以s[1]结尾的字符串有
a
以s[2]结尾的字符串有
b
ab
以s[3]结尾的字符串有
a
ba
aba
以s[4]结尾的字符串有
b
ab
bab
abab
4、indx表示当前字母上一次出现的位置,即索引
5、dp[i] = dp[i-1] + i - indx[M]
加i:在不考虑加的这个字母是否有重复的情况下,前面的所有可能都要加上当前字母,前面一共有i种情况
-indx[M]:因为当前加的这个字母可能会有重复
这种情况是第一次重复
![](https://i-blog.csdnimg.cn/blog_migrate/315c22dceef1095c2dd5e635dee54de9.png)
下面这种情况是第二次重复
![](https://i-blog.csdnimg.cn/blog_migrate/bd2b82a23c6acad9066b366c0e136626.png)
依次类推……
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int ll
const int N = 100010;
char s[N];
int dp[N];
int indx[50];//当前字母上一次出现的位置
signed main()
{
cin >> (s+1);
int ans = 0;
int len = strlen(s+1);
for(int i=1;i<=len;i++)
{
dp[i] = dp[i-1] + i - indx[int(s[i]) - int('a')];
ans += dp[i];
indx[int(s[i]) - int('a')] = i;//将字符转化成数字
}
cout << ans <<endl;
return 0;
}