审题: f ( s ) = 字符串 s 中有多少个不同的字符 f(s) = 字符串 s 中有多少个不同的字符 f(s)=字符串s中有多少个不同的字符
理解:每个字符的 “贡献值”
举例:
对于 a b a b c 的第 2 次出现的 a,有多少字符串包含这个a呢?
a 的左侧:a b a、b a、a(把 a 本身算成 a 的左侧)
a 的右侧:a b、a b c
所以,一共有 2 * 3 = 6 种字符串包含这个 a。
但是,这些字符串都会把这个 a 计数吗?显然不会。那么,有多少字符串会把这个 a 算入 f ( s ) f(s) f(s) 呢?
只有这个 a 是第一次出现时,才会对它计数。即:a b a 并不会对第 2 个 a 计数。
所以,这个 a 的贡献度是:从这个 a 往左数到 a,从这个 a 往右数到末尾(对于后面来说,这个 a 是第一次出现的),然后相乘,积就是这个 a 的贡献值。
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
// 在此输入您的代码...
String string = scan.nextLine();
char[] cArray = string.toCharArray();
int[] leftIndex = new int[26];
Arrays.fill(leftIndex, -1);
long count = 0;
int len = cArray.length;
for (int i = 0; i < len; i++) {
char c = cArray[i];
count += (long) (len - i) * (i - leftIndex[c - 'a']);
leftIndex[c - 'a'] = i;
}
System.out.print(count);
scan.close();
}
}
细节
-
“贡献值” 如何计算?
举例:a b a b c,计算中间 a 贡献值。
a 的左侧有:b a,a(2)
a 的右侧有:a b c,a b(2)那么是不是就是 2 * 2 呢?
不是!我们并没有考虑单独的左侧或者右侧作为字符串的情况。
我们看似把单独的 a 只放在了左侧,其实右侧也需要一个单独的 a。这是因为: b a 也是该 a 有贡献的子字符串,或者说 a 本身也是该 a 有贡献的字符串。可是在之前的计算中,如果取左侧单独的a,就必须和右侧的 a b c,a b 进行组合。所以,右侧也需要有一个单独的 a,这样在乘法时就可以实现 11、n1、1*n。
-
初识
leftIndex
为什么初始化为 -1?
计算贡献值的时候,比如第一个a的index=0
,那么index - leftIndex = 1
,所以为-1
。 -
关于
long
的使用1 ≤ n ≤ 105
这意味着在计算
count
时,有105*105超过int
的风险。
所以:count
设为long
;count += (long) (len - i) * (i - leftIndex[c - 'a']);