HDU 5056 Boring count(BestCoder Round #11 (Div. 2))

Problem Description:

You are given a string S consisting of lowercase letters, and your task is counting the number of substring that the number of each lowercase letter in the substring is no more than K.
 
Input:
In the first line there is an integer T , indicates the number of test cases.
For each case, the first line contains a string which only consist of lowercase letters. The second line contains an integer K.

[Technical Specification]
1<=T<= 100
1 <= the length of S <= 100000
1 <= K <= 100000
 
Output:
For each case, output a line contains the answer.
 
Sample Input:
3
abc
1
abcabc
1
abcabc
2
 
Sample Output:
6
15
21

题意:给出一个字符串s和一个整数k,问有多少s的子串满足条件,条件是子串中每个字母出现的个数不能大于k(只有小写字母)。

这里用到一个公式,一个长度为n的字符串的连续子串的个数为1+2+3+……+n。证明:举例如abcabc:我们可以分别得到该字符串长度为1,2,3,4,5,6的子串:

1:a     b     c     a     b     c;

2:ab     bc     ca     ab     bc;

3:abc     bca     cab     abc;

4:abca      bcab     cabc;

5:abcab     bcabc;

6:abcabc;

不难发现连续子串的个数和是1+2+3+……+n。

#include<stdio.h>
#include<string.h>
#include<queue>
#include<math.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;

const int N=1e5+10;
const int INF=0x3f3f3f3f;
const int MOD=1e9+7;

typedef long long LL;

char s[N];
int vis[N]; ///标记序号为i的字母出现的次数

int main ()
{
    int T, k, i, j;
    LL ans; ///这里必须用LL,不然会wa

    scanf("%d", &T);

    while (T--)
    {
        scanf("%s %d", s, &k);

        j = 0; ///当发现一个字母出现的次数>k时,j的值会改变
        ans = 0;
        memset(vis, 0, sizeof(vis));

        for (i = 0; s[i] != '\0'; i++)
        {
            vis[s[i]-'a']++;

            if (vis[s[i]-'a'] > k)
            {
                while (s[j] != s[i]) ///举例:bcaacb(k==1),当我们找到第二个a时发现a出现的次数大于k了,首先之前的bca已经算出了子串个数1+2+3,所以现在的bc的次数需要减1,j需要移到前一个a
                {
                    vis[s[j]-'a']--;
                    j++;
                }

                vis[s[i]-'a']--; ///还是上面的例子由于现在a的次数大于k,那么我们也需要将a的次数减1,j指向现在的a(当然举例:abcabc也是成功的,只是这时没有经过while循环那一步)
                j++;
            }

            ans += i-j+1; ///这里计算子串的个数,至于为什么只加上字符的个数,举例:abc:在a的时候我们会加1(可以看做加上了a这个子串),在b的时候加2(本来ab有三个子串:a,b,ab,但是之前加了a,不能重复,所以加2),那么在c的时候同理加3就好了
        }

        printf("%lld\n", ans);
    }

    return 0;
}
posted @ 2015-10-30 19:55  搁浅の记忆  阅读(127)  评论(0编辑  收藏  举报