题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5672
String
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1133 Accepted Submission(s): 367
Problem Description
There is a string
S
.
S
only contain lower case English character.
(10≤length(S)≤1,000,000)
How many substrings there are that contain at least k(1≤k≤26) distinct characters?
How many substrings there are that contain at least k(1≤k≤26) distinct characters?
Input
There are multiple test cases. The first line of input contains an integer
T(1≤T≤10)
indicating the number of test cases. For each test case:
The first line contains string S .
The second line contains a integer k(1≤k≤26) .
The first line contains string S .
The second line contains a integer k(1≤k≤26) .
Output
For each test case, output the number of substrings that contain at least
k
dictinct characters.
Sample Input
2 abcabcabca 4 abcabcabcabc 3
Sample Output
0 55
Source
有一个 10≤长度≤1,000,000 的字符串,仅由小写字母构成。求有多少个子串,包含有至少k(1≤k≤26)个不同的字母?
解题思路:采用两个指针,轮流更新左右边界,同时累加答案。
注意:1、在更换头指针的时候,需要考虑是否我用来记录的num值可以减掉,因为如果两个字符相同的话,在这个子串中不同字符的数目是不变的。
2、如果每更换一次头指针,我就把i重新再来一次,就会超时。
详见代码。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define ll long long
const int N=1e6+9;
char ch[N];
int k;
int vis[300];
int main()
{
int t;
scanf("%d",&t);
while (t--)
{
scanf("%s%d",ch,&k);
int len=strlen(ch);
int head=0,num=0;
ll ans=0;
memset(vis,0,sizeof(vis));//vis是用来表示字符出现的次数,而不是标记是否出现过
for (int i=0; i<len; i++)
{
if (vis[ch[i]]==0)//查找一段区间内不同字符的数量
num++;
vis[ch[i]]++;
while (num>=k)//只要和至少的k相同时,就可以直接的计算出后面的有多少个
{
ans+=len-i;
if (vis[ch[head]]==1)//判断这个字符是不是只出现一次,如果是的话num--,否则num不变
num--;
vis[ch[head]]--;
head++;
//memset(vis,0,sizeof(vis));
}
}
printf ("%lld\n",ans);
}
return 0;
}