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;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章