JZOJ3870 [NOIP2014八校联考第4场第1试10.19] 单词检索

Description
小可可是学校图书馆的管理员,现在他接手了一个十分棘手的任务。
由于学校需要一些材料,校长需要在文章中检索一些信息。校长一共给了小可可N篇文章,每篇文章为一个字符串。现在,校长需要他找到这样的单词,它至少在这N篇文章中的M篇文章里出现过,且单词长度为L。可是,工作量十分庞大,但校长又急需小可可完成这项任务。
现在他向你求助,需要你编写程序完成这项艰巨的任务。
Input
第1行3个正整数N,M,L,表示文章的数目,单词至少出现在M篇文章中和每个单词的长度。
接下来N行,每行一个字符串,表示一篇文章。
Output
仅一行,表示满足检索条件的单词数。
Data Constraint
对于20%的数据有1≤N,M≤10;
对于60%的数据有1≤N,M≤100;
对于100%的数据有1≤N,M≤2000,L≤1000。每篇文章长度不大于1000,均有小写字母组成。
Solution
Hash,开散列,单哈希注意模数在2000多万,可能需要开short int,卡卡空间就过了
Code

#include <cstdio>
#include <cstring>

#define ll long long

using namespace std;

const int maxn = 2007;
const ll mo = 28282789, moo = 31153;
short int ha[mo + 5], n, m, len, bo[mo + 5], id;
short int ha2[mo + 5];
ll tmp[maxn];
ll ans;
char s[maxn];
bool bz[mo + 10];

int hash(ll x)
{
    ll y = x % mo;
    while (ha[y] != x % moo && ha[y]) y = y % mo + 1;
    if (!ha[y]) ha[y] = x % moo; 
    if (bo[x] < id) ++ ha2[y], bo[x] = id;
    return y;
}

int main()
{
    scanf("%d%d%d", &n, &m, &len);
    tmp[len] = 1;
    for (int i = len - 1; i >= 1; -- i) tmp[i] = tmp[i + 1] * 26 % mo;
    for (int i = 1; i <= n; ++ i)
    {
        scanf("%s", s + 1);
        int nowlen = strlen(s + 1);
        if (nowlen < len) continue;
        ll value = 0;
        ++ id;
        for (int i = 1; i <= len; ++ i)
            value = (value + tmp[i] * s[i]) % mo;

        int x = hash(value);
        if (ha2[x] >= m && !bz[x]) ++ ans, bz[x] = true;

        for (int i = len + 1; i <= nowlen; ++ i)
        {
            int pre = i - len;
            value = (((value - s[pre] * tmp[1]) % mo + mo) % mo * 26 + s[i]) % mo;

            x = hash(value);
            if (ha2[x] >= m && !bz[x]) ++ ans, bz[x] = true;
        }
    }
    printf("%lld\n", ans);
    return 0;
} 
发布了5 篇原创文章 · 获赞 4 · 访问量 191

猜你喜欢

转载自blog.csdn.net/Partitioning/article/details/104524806