题目连接:
传送门
#include<iostream>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N = 30;
const int M = 1000010;
int t, k, cnt[N];
char str[M];
int main() {
scanf("%d", &t);
while(t--) {
//输入数据
scanf("%s", str);
scanf("%d", &k);
//初始化数据
memset(cnt, 0, sizeof cnt);
int n = strlen(str), f = 0;
ll ans = 0;
//尺取
for(int i = 0, j = 0; i < n; i++) {
//判断当前尺子上是否存在k个不同的字符
while(j < n && f < k) {
//当前字符未出现过则f++
if(cnt[str[j] - 'a'] == 0) f++;
cnt[str[j] - 'a']++;
j++;
}
//如果f的个数符合要求
if(f == k) {
ans += n - j + 1;
}
//尺头移出时数量要减一
cnt[str[i] - 'a']--;
//若该字符在尺子中再不出现则f--
if(cnt[str[i] - 'a'] == 0) f--;
}
printf("%lld\n", ans);
}
return 0;
}
这道题可以用尺取法来做
接下来讲讲尺取的方法:
首先设置几个变量,f代表当前尺子上的不同类字符的个数,cnt数组记录当某字符出现过多少次,
然后讲讲思路:尺子头尾都指向第一个字符,每次将尺尾往后移动,每次移动时判断当前,当前尺尾的字母在尺子中是否出现过,如果未出现则让 f 的数量加一,同时当前字符在尺子上出现的数量要加一,尺尾往后移,直到 f 的数量等于要求的k为止。此时前一段满足,则后面的字符加入该串中也能形成符合条件的串,因此ans += n - j + 1。当记录完后,把尺头往前,往前移动时,要把对应的字符尺子中删去,即尺头对应的字符的数量要减一。同时如果这个尺子上再没有同种字符的话,就要让 f 减一。以此类推。
最后注意ans要开long long