有一个明显的性质:如果子串(i,j)(i,j)(i,j)包含了至少kkk个不同的字符,那么子串(i,k),(j<k<length)(i,k),(j < k < length)(i,k),(j<k<length)也包含了至少kkk个不同字符。
因此对于每一个左边界,只要找到最小的满足条件的右边界,就能在O(1)O(1)O(1)时间内统计完所有以这个左边界开始的符合条件的子串。
寻找这个右边界,是经典的追赶法(尺取法,双指针法)问题。维护两个指针(数组下标),轮流更新左右边界,同时累加答案即可。复杂度 O(length(S))O(length(S))O(length(S))。
2 abcabcabca 4 abcabcabcabc 3
0 55
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <queue> #include <stack> #include <algorithm> #include <set> #define LL long long using namespace std; char s[1000010]; int A[128]; int cnt; LL ans; int main() { int t,len,p; cin>>t; while(t--) { scanf("%s",s); scanf("%d",&p); memset(A,0,sizeof(A)); ans=0; cnt=0; len=strlen(s); for(int i=0,j=0;i<len;i++) { while(j<len&&cnt<p) { A[s[j]]++; if(A[s[j]]==1) { cnt++; } j++; } if(cnt>=p) ans+=len-j+1; else break; A[s[i]]--; if(A[s[i]]==0) cnt--; } printf("%I64d\n",ans); } return 0; }