问题描述
对于一个字符串 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
Data
样例输出
28
Data
样例说明
子串 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
对于所有评测用例,1≤n≤100000。
思路:【1】假设当前字符没出现过,那么每个字符出现的总次数为:当前字符到首字符的字符数 * 当前字符到末尾字符的字符数,举例:例子中的第二个b(首次出现),第一个a到它就是2,它自己到最后的c就是4,那出现的总次数就为2*4=8(有些排列组合的意思,前面2个ab就有ab,b两种,后面部分就有b,ba,bab,babc 四种,则相乘一共8种情况)
【2】若当前字符是出现过的,例如例子中的第三个字符a,我们直接把上一次出现的a及之前的所有字符都忽略,字符串就变成babc(对于a来说,它就是首次出现),那我们再根据上面的做法即可,即2*3=6
#include<iostream>
#include<map>
using namespace std;
typedef long long ll;
int main() {
map<char, ll>a;//前者记录当前字符,后者记录当前下标i
string n;
cin >> n;
ll len = n.size();
ll sum = 0;
for (ll i = 0; i <= len - 1; i++)
{
if (a.count(n[i]))//判断当前的字符n[i]是否出现过
{//情况1:n[i]出现过
//len-i为当前第i个字符到最后一个字符的字符数
//a[n[i]]为上次该字符出现时记录的下标,
//i-a[n[i]]为上一个相同字符的下一个字符到当前字符的字符数
sum += ((len - i) * (i - a[n[i]]));
a[n[i]] = i;//计算完再更改该字符的下标为当前的i
}
else
{
//情况2:n[i]没出现过
a[n[i]] = i;//记录该字符出现的下标
sum += ((len - i) * (i + 1));
//i+1为首个字符到当前第i个字符的字符数
//len-i为当前第i个字符到最后一个字符的字符数
}
}
cout << sum;
return 0;
system("pause");
}