问题如下
看到题目第一想法是进行暴力解决(通过遍历所有的子串然后进行累加把结果得出来),结果果然是超过时间限制。
之后通过寻找字符间的规律可以得到一个式子,通过这个式子可以得到遍历一次就可以把子串分值都加起来,这样就不会超过时间限制了。
例如:s = "ababc"的这个字符串
- 第一个字符a他只出现了五次,我们就可以相当于用它的下标(假设下标从0开始),就可以得到(下标 + 1)x(s长度 - 下标) = 1x5 = 5,并且把a出现的位置记录下来,a的位置为1。
- 第二个字符b同理出现的次数为(下标 + 1)x(s长度 - 下标)= 2x4 = 8,并且把b的位置记录下来,b位置为2。
- 第三个字符是a,此前a的位置已经出现过了,实质第三个a出现过9次,但根据题目有用的只有6次,这里就可以用到((s长度 - 下标))x((当前位置 - 前一个位置)) = 3x2 = 6。
- 第四个同理第三个a,((s长度 - 下标))x((当前位置 - 前一个位置)) = 2x2 = 4。
- 第五个字符c还没有出现过所以直接(下标 + 1)x(s长度 - 下标) = 5x1 = 5。
- 从而得到ababc对应得是5,8,6,4,5加起来28。
代码如下:
#include<stdio.h>
#include<string.h>
int main()
{
long long i,n,sum = 0;
int a[26] = {0}; //代表每个字符的出现位置当为0的时候表示之前没有出现过
char s[100000];
scanf("%s",s);
n = strlen(s);
for(i = 0; i < n; i++)
{
if(a[s[i] - 'a'] == 0) //判断该字符是否出现过
{
sum = sum + (i + 1)*(n - i); //把单个字符的值加起来((下标 + 1)x(s长度 - 下标) )
a[s[i] - 'a'] = i + 1; //保存字符的位置
}
else
{
sum = sum + (i + 1 - a[s[i] - 'a']) * (n - i); //之前出现过的字符,现在再次出现的值((s长度 - 下标))x((当前位置 - 前一个位置))
a[s[i] - 'a'] = i + 1; //更新位置
}
}
printf("%lld",sum);
return 0;
}