hdu5672 String(尺取法)

来源:互联网 发布:女装品牌 知乎 编辑:程序博客网 时间:2024/05/17 04:52

题目链接:点这里!!!!


题意:

给你一个仅含小写字母的字符串s(1<=length(s)<=1000000),再给一个k(1<=k<=26),

问你存在多少个子串包含至少k个不同的字符。


题解:

很容易想到的一个思路是固定子串的左端点,然后找最近的右端点使得其刚好包含k个不同的字符,比它更右的右端点自然也符合条件。但是我们要在O(n)的时间里完成,其实我们发现相邻的两个左端点i,i+1,一开始只是差了个i,所以很容易发现左右端点在枚举的时候是单调的,所以我们可以在O(n)的时间里就能完成。具体的看代码。


代码:


#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#define LL __int64const int N = 1E6+16;using namespace std;int k;char s[N];int vis[40];int main(){    int T;    scanf("%d",&T);    while(T--){        memset(vis,0,sizeof(vis));        scanf("%s",s);        int n=strlen(s);        scanf("%d",&k);        for(int i=0;i<n;i++) s[i]-='a';        int cnt=0,r=0;        LL ans=0;        while(r<n){            if(!vis[s[r]]) cnt++;            vis[s[r]]++;            if(cnt==k) break;            r++;        }        if(cnt<k){            printf("0\n");            continue;        }        ans+=1ll*(n-r);        for(int i=1;i<n;i++){            vis[s[i-1]]--;            if(vis[s[i-1]]) {                ans+=1ll*(n-r);            }            else {                cnt--;                r++;                while(r<n){                    if(!vis[s[r]]) cnt++;                    vis[s[r]]++;                    if(cnt>=k) break;                    r++;                }                ans+=1ll*(n-r);            }            if(cnt<k) break;        }        printf("%I64d\n",ans);    }    return 0;}


0 0