题解:
先回忆一下“子串分值”系列I的“子串分值”题目是怎么做的:
题目中比较重要的信息就是 f的值仅受到在连续字串中出现一次的字符的影响。直接统计所有子串中单个字符的个数时间上过不去,那么,我们可以考虑单个字符带来的贡献度。(核心思想:换位思考)
看样例:‘ababc’
我们看第二个a,虽然它可以处于多个子串中,但是如果这个子串里面还包含了其它a的话,那么这个’a’就不能对f的值产生贡献(使f的总和增加)了。而它每处于一个有效子串(除开它自己没有别的a的子串)中,f的总值就增加1。第二个a:
在子串‘aba*‘中对f值无贡献 (*表示任意后续,可为空)
在子串’a’,‘ab’,‘abc’,‘ba’,‘bab’,'babc’中均对f值贡献了1,总共贡献6
所以,我们统计每一个字符处于多少个有效子串中即可计算出f的总和。如何计算有效子串呢?
还是看刚刚的第二个’a’,它所处的子串要有效,就得不能包含别的‘a‘。那么我们先找到不包含其他’a’的最长子串:‘babc’
现在要做的就是找到这个串中包含’a’的连续子串的个数,如何找呢?
可以这样考虑,由于要包含’a‘,那么子串中a前面的字符选择就有:
‘b’,’’(空) 共2种情况
后面的字符选择有:‘’(空),‘b’,‘bc’ 共3种情况
那么子串的情况就有 2×3=6种。( 即(a前面的字符个数+1) × ( a后面的字符个数+1)或 (该’a’的下标 - 上个‘a’的下标)×(下个’a’的下标 - 该’a’的下标))
与这道题不同的是,本题字串可以存在同一个字母,但要考虑到贡献度时,也应注意!
理解以下几点:
1.我们对每个字母的贡献值进行累加即可得到正确答案。
2.每个字母的贡献值:首先理解一下:对于任意一个在字符串中的字母,所有包含这个字母子串的个数算法:字母初始时“上一次“”出现的位置设为-1,(本次出现的位置-上次出现的位置)*(将来最近一次出现的位置-本次出现的位置),这个可以用题目例子枚举一下,然后就会发现这个式子的含义。解决了这个问题之后,还有一个“作用域”的问题(就是一个字母在什么范围内才会对结果做出贡献),在本题中,一个字母的作用域为:上次出现这个字母的位置——整个字符串结束(解释:当一个字母出现后,之后如果再出现,结果是不会增加的,所以之后再出现的字母对结果不做贡献。上次出现到---整个字符结束,这整个字符串及包含这个字母的子串(上面对此数量算法已作出解释)都要对结果做一次贡献。)
3.遍历字符串,计算每个字母的贡献值,累加即可。“子串分值”题类似思路,作用于不同而已。
(这个思路是对于“子串分值”和“子串分值和”都通用的公式,在这个题中所谓的“将来最近一次出现的位置”就是字符串长度的位置。原因:一个字符出现,随后再出现,这个随后再出现是对结果不做贡献的,所以出不出现无所谓,可以直接滑到最后。但如果要考虑这个字母给整个子串带来的贡献度,仍要保证当前位置之前不具有相同字母。因此那个“将来最近一次出现的位置”直接写字符串长度就可以了。可以做一下“子串分值”那道题,可以有更深的理解)
## 解题思路
请填写解题思路
```
import os
import sys
# 请在此输入您的代码
s=input()
node="a"
ans=0
while ord(node)<=ord("z"):
li=[]
if node in s:
li.append(-1)
for i in range(len(s)):
if node==s[i]:
li.append(i)
li.append(len(s))
for i in range(1,len(li)):
ans+=(li[i]-li[i-1])*(li[-1]-li[i])
node=chr(ord(node)+1)
print(ans)
```