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;
}