解法
首先,通过(start,end,counter)
来标识每个单词。
坑点有三:
- 搜索时不需要遍历单词数组,只需要从
S
中截取字符串,判断它是否在单词的哈希集合里 - 生成字符串的
a
,b
,c
,d
还有x
都得是长整型!!! - 优化的点在于如何在长字符串里搜索,由于所有单词加在一起的长度不超过
1
0
5
10^5
105,所以单词长度的种类数不超过
1
0
2.5
10^{2.5}
102.5,当长度固定时,在
S
上做滑动窗口,比每次都单独substr
要快。所以最后用一个set<int>
存长度,用另一个unordered_map<WORD,int>
来存每个单词的个数,每匹配上一个WORD
就删除一个。
#include <stdio.h>
#include <unordered_map>
#include <string>
#include <iostream>
#include <memory.h>
#include <stdlib.h>
#include <set>
#include <functional>
using namespace std;
class WORD {
public:
char s,e;
unsigned short key[26];
WORD(string str) {
s = str[0]; e = str[str.size()-1];
memset(key,0,sizeof(unsigned short)*26);
for(auto &c:str) {
key[c-'a']++;
}
}
bool operator == (const WORD &b) const {
if (s==b.s) {
if (e==b.e) {
for(int i=0;i<26;++i)
if (key[i]!=b.key[i]) return false;
return true;
}
return false;
}
return false;
}
};
namespace std {
template <>
class hash<WORD> {
public:
size_t operator () (const WORD &a) const {
auto ch = hash<char>();
auto un = hash<unsigned short>();
size_t ans = ch(a.s);
ans ^= ch(a.e);
for(auto &c:a.key) {
ans ^= un(c);
}
return ans;
}
};
}
int main() {
int t;
cin>>t;
for(int round=1;round<=t;++round) {
int l;
cin>>l;
unordered_map<WORD, int> dict;
set<int> lengths;
for(int i=0;i<l;++i) {
string str;
cin>>str;
dict[WORD(str)]++;
lengths.insert(str.size());
}
string s1,s2;
int n;
long long a,b,c,d;
cin>>s1>>s2>>n>>a>>b>>c>>d;
long long x1 = s1[0], x2 = s2[0];
string str = s1+s2;
for(int i=3;i<=n;++i) {
int tmp = x2;
x2 = (a*x2+b*x1+c)%d;
x1 = tmp;
str += char('a'+(x2%26));
}
int ans=0;
for(auto &ll:lengths) {
if (ll>n) break;
WORD temp(str.substr(0,ll-1));
int i=0;
do {
temp.e = str[i+ll-1];
temp.key[temp.e-'a']++;
auto it = dict.find(temp);
if (it!=dict.end()) {
ans += it->second;
dict.erase(it);
}
temp.key[temp.s-'a']--;
temp.s = str[++i];
} while (i+ll-1<n);
}
printf("Case #%d: %d\n",round,ans);
}
}