hdu 4821 string(哈希)

点击打开链接


代码:

#include<iostream>
#include<string>
#include<cstdio>
#include<map>
#define getHashval(n, l) hv[n] - hv[n+l] * nbase[l]
using namespace std;

typedef unsigned long long ULL;

const int base = 31;
ULL hv[100000+1];
ULL nbase[100000+1];
map<ULL, int> hashmap; // 类型为map,实际当作一个集合来使用

int main()
{
    int m, l, count;
    string s;
    nbase[0] = 1;
    for(int i=1; i<=100000; i++)
        nbase[i] = nbase[i-1] * base;
    while(scanf("%d%d", &m, &l) != EOF)
    {
        cin >> s;
        count = 0;
        int len = (int)s.length();
        hv[len] = 0;
        for(int i=len-1; i>=0; i--)
            hv[i] = hv[i+1] * base + s.at(i);

        // 窗口A,长度为m*l,在输入字符串上滑动,每次滑动1个字符,可以看到len-m*l+1个字串
        int end = len-m*l;
        for(int i=0; i<l && i<=end; i++)
        {
            hashmap.clear();//哈希值集合初始化:清空
            // 将长度为m*l的串,切割为长度为l的m个子串,分别将各个子串的哈希值放入hashmap集合
            // map中,map的key是子串的哈希值,map的值是一个计数,即相同哈希值出现n次的话则值为n
            for(int j=i; j<i+m*l; j+=l)
                hashmap[getHashval(j, l)]++;
            if((int)hashmap.size() == m)
                count++;
            // 窗口B,长度为m*l,开始与窗口A重合,每次向右滑动l个字符,到窗口右边与字符右边对齐为止
            // 每滑动一次B窗口,将最左边那长度l子串的哈希值移出hashmap集合,右边子串的哈希值添加到集合
            int end2 = len-m*l-l;
            for (int j=i; j<=end2; j+=l)
            {
                ULL temp = getHashval(j, l);
                hashmap[temp]--;
                if(hashmap[temp] == 0)
                    hashmap.erase(temp);
                hashmap[getHashval(j+m*l, l)]++;
                if((int)hashmap.size() == m)
                    count++;
            }
        }
        printf("%d\n",count);
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/Egqawkq/article/details/78587909