而有魔法的子串被定义为
S
S
S的某一非空子串,满足该子串中不同的字符数为
k
k
k,且每个字符的出现的次数都相同。
你需要求出给定字符串
S
S
S的不同的有魔法的子串的个数。
若两个子串的左右端点不同,则这两个子串不同。
对于所有数据,保证
2
≤
n
≤
1
0
5
2le nle 10^5
2≤n≤105,字符集为
[
a
,
z
]
∪
[
A
,
Z
]
[a,z]∪[A,Z]
[a,z]∪[A,Z]。
题解
会发现一个区间如果满足条件,那么每种字符前缀和在
r
r
r位置和
l
−
1
l-1
l−1位置之差都相等,
换种角度考虑,
r
r
r位置和
l
−
1
l-1
l−1位置下,每两种字符前缀和之差都相等,
所以可以把前缀和每个位置的各个字符和字符
a
a
a的值之差列出来,相同的两个位置代表的区间即符合条件,直接排序即可。
代码
#include<cstdio>#include<cstring>#include<algorithm>usingnamespace std;#define N 100010char s[N];int f[55], p[55], r =0;struct node {int p[55];}a[N];intcmp(node x, node y){for(int i =0; i < r; i++){if(x.p[i]< y.p[i])return1;if(x.p[i]> y.p[i])return0;}return0;}intmain(){int n, i, j;scanf("%d",&n);scanf("%s", s +1);for(i =1; i <= n; i++){if(s[i]<='Z') p[s[i]-'A']=1;else p[s[i]-'a'+26]=1;}for(i =0; i <52; i++){if(p[i]) p[i]= r, r++;}for(i =1; i <= n; i++){if(s[i]<='Z') f[p[s[i]-'A']]++;else f[p[s[i]-'a'+26]]++;for(j =0; j < r; j++) a[i].p[j]= f[j]- f[0];}sort(a, a + n +1, cmp);longlong ans =0, t =0;for(i =0; i <= n; i++){if(i ==0||cmp(a[i -1], a[i])==1){
t =1;}else{
ans += t;
t++;}}printf("%lld", ans %1000000007);return0;}