HDU 4821 String 解题报告(哈希)

来源:互联网 发布:中国汽车年度销量数据 编辑:程序博客网 时间:2024/06/10 19:39

String

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 773    Accepted Submission(s): 216


Problem Description
Given a string S and two integers L and M, we consider a substring of S as “recoverable” if and only if
  (i) It is of length M*L;
  (ii) It can be constructed by concatenating M “diversified” substrings of S, where each of these substrings has length L; two strings are considered as “diversified” if they don’t have the same character for every position.

Two substrings of S are considered as “different” if they are cut from different part of S. For example, string "aa" has 3 different substrings "aa", "a" and "a".

Your task is to calculate the number of different “recoverable” substrings of S.
 

Input
The input contains multiple test cases, proceeding to the End of File.

The first line of each test case has two space-separated integers M and L.

The second ine of each test case has a string S, which consists of only lowercase letters.

The length of S is not larger than 10^5, and 1 ≤ M * L ≤ the length of S.
 

Output
For each test case, output the answer in a single line.
 

Sample Input
3 3abcabcbcaabc
 

Sample Output
2
 

Source
2013 Asia Regional Changchun
 

    解题报告: 求连续m个长度为 l 的子串两两不相同的数量。
    首先,对比长度为 l 的字串是否相同,我们可以用字符串哈希的方法。然后我们使用Hash表,将(0, l-1)的子串哈希值插入哈希表,标记为1,(l, 2l - 1)的子串哈希值插入哈希表,标记为2。。。如果发现某次的哈希值已经标记过,且标记的值与当前的将要标记的值的差值小于m,那么说明这里有部分m个长度为 l 的连续串不符合条件。最后用总数减去不符合条件的即可。代码如下:

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <vector>#include <map>#include <set>#include <string>#include <iomanip>#include <cassert>using namespace std;//#pragma comment(linker, "/STACK:1024000000,1024000000")#define ff(i, n) for(int i=0;i<(n);i++)#define fff(i, n, m) for(int i=(n);i<=(m);i++)#define dff(i, n, m) for(int i=(n);i>=(m);i--)#define bit(n) (1LL<<(n))typedef long long LL;typedef unsigned long long ULL;void work();int main(){#ifdef ACM    freopen("in.txt", "r", stdin);#endif // ACM    work();}void nextInt(int & x){    char ch;    while(ch = getchar(), isdigit(ch) == false);    x = 0;    while(x = 10 * x + ch - '0', ch = getchar(), isdigit(ch) == true);}/*****************************************华丽分割线**********************************************/int m, l;/********************************************************* * 无清空哈希表。闭哈希,long long 对比,保存Size大小。* * 可直接遍历哈希状态,每次使用时init下。              * *********************************************************/template<int Size>struct HashTable{    int v[Size];    int h[Size];    int n[Size];    ULL s[Size];    int size, id, num;    void init()    {        ++id;        size = 0;    }    int push(ULL ss)    {        num++;        int i = ss % Size;        while (v[i] == id && s[h[i]] != ss)            if(++i == Size)                i = 0;        if (v[i] == id)        {            int ret = num - n[h[i]];            n[h[i]] = num;            return ret;        }        else        {            s[size] = ss;            n[size] = num;            h[i] = size++;            v[i] = id;            return Size;        }    }};HashTable<1000003> ht;ULL powULL(ULL a, int b){    ULL ret = 1;    while(b)    {        if(b&1)            ret = ret * a;        a = a * a;        b >>= 1;    }    return ret;}/********************************************************* * 字符串哈希大法                                       * *********************************************************/template<int Size>struct HashString{    ULL h[Size];    ULL powull;    void init(char * s, int len = -1)    {        powull = powULL(29, l);        if(len == -1) len = strlen(s);        ff(i, len)            h[i+1] = h[i] * 29 + s[i] - 'a';    }    ULL get(int sta, int len)    {        return h[sta + len] - h[sta] * powull;    }};HashString<111111> hs;char str[111111];void work(){    while(scanf("%d%d", &m, &l) == 2)    {        scanf("%s", str);        int len = strlen(str);        hs.init(str, len);        int ans = 0;        ff(sta, l)        {            ht.init();            int ti = (len - sta) / l;            int mt = ti - m + 1;            if (mt <= 0) continue;            int res = 0;            int wws = -1, wwe = -2;            ff(i, ti)            {                int sub = ht.push(hs.get(sta + i * l, l));                if (sub >= m) continue;                int ws = max(0, i-m+1);                int we = min(i-sub, mt-1);                if (ws <= wwe)                {                    wwe = max(wwe, we);                }                else                {                    res += wwe - wws + 1;                    wws = ws, wwe = we;                }            }            res += wwe - wws + 1;            ans += mt - res;        }        printf("%d\n", ans);    }}


0 0
原创粉丝点击