题目描述
对于一个字符串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。
算法描述:究其根本,是一种减少时间复杂度的算法——减少不必要的比较和存储步骤
我们可以通过求每个字符对数列的贡献度来解决问题,每个字符的贡献度都是等于该字符距离上一个和它一样的字符之间的个数乘以它到字符串末尾的个数。
以题例 ababc 为例子,这五个字符每个字符的贡献度分别为:
a: 1*2=2;
b: 2*2=4;
a:2*3=6;
b: 2*2=4;
c: 5*1=5
所以正好加起来等于21;
#include<stdio.h>
#include<string.h>
int main()
{
char a[100000]={0};//输入字串
int len,sum=0;//记录长度和个数和
scanf("%s",a);
len=strlen(a);
for(int i=0;i<len;i++)//遍历
{
char temp=a[i];//基准点
int qwq1=1,qwq2=1,index=i;
for(int j=index;j>=0;j--)//向左遍历比较
{
if(a[j]!=temp)
{
qwq1++;
if(j==0)
{
break;
}
}
if(a[j]==temp&&j!=index)
{
break;
}
}
for(int j=index;j<len;j++)//向右遍历比较
{
if(a[j]!=temp)
{
qwq2++;
if(j==len-1)
{
break;
}
}
if(a[j]==temp&&j!=index)
{
break;
}
}
int gx=qwq1*qwq2;//公式(左右相乘)
sum+=gx;
}
printf("%d\n",sum);
return 0;
}
PS:原理我说不太清楚,这里就不赘述了