HDU 5672 String(尺取法)——BestCoder Round #81(div.1 div.2)

String

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 0    Accepted Submission(s): 0


Problem Description
There is a string  S . S  only contain lower case English character. (10length(S)1,000,000)
How many substrings there are that contain at least  k(1k26)  distinct characters?
 

Input
There are multiple test cases. The first line of input contains an integer  T(1T10)  indicating the number of test cases. For each test case:

The first line contains string  S .
The second line contains a integer  k(1k26) .
 

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
BestCoder Round #81 (div.2)
 

/************************************************************************/

附上该题对应的中文题

String

 
 
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
问题描述
有一个 10\leq10长度\leq 1,000,0001,000,000 的字符串,仅由小写字母构成。求有多少个子串,包含有至少k(1 \leq k \leq 26)k(1k26)个不同的字母?
输入描述
输入包含多组数据. 第一行有一个整数T (1\leq T\leq 10)T(1T10), 表示测试数据的组数. 对于每组数据:
第一行输入字符串SS。
第二行输入一个整数kk
输出描述
对于每组数据,输出符合要求的子串的个数。
输入样例
2
abcabcabca
4
abcabcabcabc
3
输出样例
0
55
/****************************************************/

出题人的解题思路:

String

有一个明显的性质:如果子串(i,j)(i,j)包含了至少kk个不同的字符,那么子串(i,k),(j < k < length)(i,k),(j<k<length)也包含了至少kk个不同字符。

因此对于每一个左边界,只要找到最小的满足条件的右边界,就能在O(1)O(1)时间内统计完所有以这个左边界开始的符合条件的子串。

寻找这个右边界,是经典的追赶法(尺取法,双指针法)问题。维护两个指针(数组下标),轮流更新左右边界,同时累加答案即可。复杂度 O(length(S))O(length(S))

比较好用的尺取法,很多串操作中都会用到,推荐好好学一下
"算法初步——尺取法"→尺取法
建议下载下来看,有动画,利于理解
从字符串首地址开始,利用i,j两个下标维护,当区间[i,j]内满足有k个不同字符,那么区间[i,r](r>j)内必定满足至少k个不同字符直到区间[i,strlen(s)],那么就有符合的strlen(s)-j个子串,然后更新i即可
还得早起参加省赛,就先到这了
/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<deque>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
#define ll long long
using namespace std;
const int N = 1000005;
const int M = 10000;
const int inf = 100000000;
const int mod = 2009;
char s[N];
int v[30];
int main()
{
    int t,m,k,p,i,j,len,c;
    __int64 sum;
    int n;
    scanf("%d",&t);
    while(t--)
    {
        memset(v,0,sizeof(v));
        scanf("%s%d",s,&n);
        len=strlen(s);
        sum=c=p=0;
        for(i=0;i<len;i++)
        {
            if(!v[s[i]-'a'])
                c++;
            v[s[i]-'a']++;
            if(c >= n)
            {
                sum=sum+len-i ;
                for(j=p;j<len;++j)
                {
                    
                    v[s[j]-'a']--;
                    if(!v[s[j]-'a'])
                        c--;
                    if(c<n) 
                        break;
                    sum=sum+len-i ;
                }
                p=j+1;
            }
        }
        printf("%I64d\n",sum);
    }
    return 0;
}
菜鸟成长记

你可能感兴趣的:(ACM,尺取法)