有一個明顯的性質:如果子串(i,j)包含了至少k個不同的字符,那麼子串(i,k),(j<k<length)也包含了至少k個不同字符。
因此對於每一個左邊界,只要找到最小的滿足條件的右邊界,就能在O(1)時間內統計完所有以這個左邊界開始的符合條件的子串。
尋找這個右邊界,是經典的追趕法(尺取法,雙指針法)問題。維護兩個指針(數組下標),輪流更新左右邊界,同時累加答案即可。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 1000005;
char str[N];
int vis[30];
int main()
{
int T, n, len;
cin>>T;
while(T--)
{
int cnt = 0;
int sum = 0;
scanf("%s%d", &str, &n);
LL result = 0;
len = strlen(str);
memset(vis, 0, sizeof(vis));
for(int i=0 ;i<len; i++)
{
if(!vis[str[i]-'a'])
sum++;
vis[str[i]-'a'] ++;
while(sum == n)
{
result += len-i;
vis[str[cnt]-'a']--;
if(!vis[str[cnt]-'a'])
{
sum--;
cnt++;
break;
}
cnt++;
}
}
cout<<result<<endl;
}
return 0;
}