题目链接
题目描述
题目描述
对于一个字符串S,我们定义S 的分值 f(S) 为S中恰好出现一次的字符个数。例如f (”aba”) = 1,f (”abc”) = 3, f (”aaa”) = 0。
现在给定一个字符串S[0…n-1](长度为n),请你计算对于所有S的非空子串S[i…j](0 ≤ i ≤ j < n), f (S[i… j]) 的和是多少。
输入
输入一行包含一个由小写字母组成的字符串S。
输出
输出一个整数表示答案。
样例输入复制
ababc
样例输出复制
21
提示
样例说明:
子串f值:
a 1
ab 2
aba 1
abab 0
ababc 1
b 1
ba 2
bab 1
babc 2
a 1
ab 2
abc 3
b 1
bc 2
c 1
对于20% 的评测用例,1 ≤ n ≤ 10;
对于40% 的评测用例,1 ≤ n ≤ 100;
对于50% 的评测用例,1 ≤ n ≤ 1000;
对于60% 的评测用例,1 ≤ n ≤ 10000;
对于所有评测用例,1 ≤ n ≤ 100000。
解题思路
通过观察数据范围,发现如果有两重for循环也会超时,所以必须时间复杂度小于O(n²)
PAT1093很像,可以一起做一下
具体思路是求出当前字母上一次出现的位置和下一次出现的位置,然后用两个位置与当前的值作差后相乘即可
比如题目中的例子
题解
#include<iostream>
#include<map>
using namespace std;
int pre[100005];
int post[100005];
map<char,int> ma;
int main(){
string s;
cin>>s;
s='0'+s;
for(int i=1;i<s.length();i++){
pre[i]=ma[s[i]];
ma[s[i]]=i;
}
int len=s.length();
for(int i=0;i<26;i++){
ma[i+'a']=len;
}
// for(int i=1;i<s.length();i++){
// cout<<pre[i]<<" ";
// }
// cout<<endl;
for(int i=s.length()-1;i>=1;i--){
post[i]=ma[s[i]];
ma[s[i]]=i;
}
// for(int i=1;i<s.length();i++){
// cout<<post[i]<<" ";
// }
// cout<<endl;
int ans=0;
//cout<<s.length()<<endl;
for(int i=1;i<s.length();i++){
ans+=(post[i]-i)*(i-pre[i]);
//cout<<ans<<endl;
}
cout<<ans;
}