一个比较关键的地方是, 集合中不存在相同的字符串。
还有就是对字符串按长度从小到大排序, 排序后就简单了很多
对于 (A) 集合来说, 对于一个当前串, 可以枚举它的前缀, 看之前是否出现过,如果出现过, 把后半部分存下来
对于 (B) 集合来说, 对于一个当前串, 可以枚举它的后缀, 如果之前出现过, 把前半部分存下来
并存下每个 hash
值对应的原来位置
在统计答案的时候,
对于集合 A
, 对于一个当前串, 枚举它的前缀, 如果出现过,并且后半部分在 B
中作为差值出现过, 则说明该串和它的前缀串都不是特殊的, 利用之前存下来的 hash
到 pos
的映射, 可以找到这个前缀的位置, 给他们俩都打上标记
对于 B
也是类似的操作
使用 hash + map
即可实现
碰到一个奇怪的地方, 以下是一份 wa
掉的代码
const ull base = 163;
void input(){
cin >> s;
len = s.size();
hash = new ull[len];
for(int i = 0;i < len;i++){
if(i == 0) hash[i] = s[i] - 'a';
else hash[i] = base * hash[i-1] + s[i] - 'a';
}
}
问题在于 s[i] - 'a'
, 直接使用 s[i]
即可 AC
是从碰撞的概率来解释吗, 没有仔细考虑过, 可以 m 一下
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N = 1e6 + 10, M = 1e5 + 10;
const ull base = 163;
ull p[N];
void init(){
p[0] = 1;
for(int i = 1;i < N;i++) p[i] = p[i-1] * base;
}
struct HashString{
string s;
ull* hash;
int len;
void input(){
cin >> s;
len = s.size();
hash = new ull[len + 10];
for(int i = 0;i < len;i++){
if(i == 0) hash[i] = ull(s[i]);
else hash[i] = base * hash[i-1] + ull(s[i]);
}
}
ull get(int l,int r){
if(l == 0) return hash[r];
return hash[r] - hash[l-1] * p[r-l+1];
}
ull getHash(){ return hash[len - 1]; }
}s[M], t[M];
int n, m;
map<ull, int> visA, posA;
map<ull, int> visB, posB;
int a[N], b[N];
int main() {
//HashString::init();
ios::sync_with_stdio(false);
cin >> n >> m;
init();
for (int i = 1; i <= n; i++) s[i].input();
for (int j = 1; j <= m; j++) t[j].input();
auto cmp = [](HashString& a, HashString& b){
return a.len < b.len;
};
sort(s + 1,s + 1 + n, cmp);
sort(t + 1,t + 1 + m, cmp);
for(int i = 1;i <= n;i++){
posA[s[i].getHash()] = i;
for(int j = 0;j < s[i].len - 1;j++){
ull preHash = s[i].get(0, j);
if(posA.count(preHash)){
//cout << s[i].s.substr(j + 1, s[i].len - 1 - j) << '
';
visA[s[i].get(j + 1, s[i].len - 1)] = true;
}
}
}
for(int i = 1;i <= m;i++){
posB[t[i].getHash()] = i;
for(int j = 0;j < t[i].len - 1;j++){
ull sufHash = t[i].get(j + 1, t[i].len - 1);
if(posB.count(sufHash)){
//cout << t[i].s.substr(0, j + 1) << '
';
visB[t[i].get(0, j)] = true;
}
}
}
for(int i = 1;i <= n;i++){
for(int j = 0;j < s[i].len - 1;j++){
if(posA.count(s[i].get(0, j)) and visB.count(s[i].get(j + 1, s[i].len - 1))){
a[i] = a[posA[s[i].get(0, j)]] = 1;
}
}
}
for(int i = 1;i <= m;i++){
for(int j = 0;j < t[i].len - 1;j++){
if(posB.count(t[i].get(j + 1, t[i].len - 1)) and visA.count(t[i].get(0, j))){
b[i] = b[posB[t[i].get(j + 1, t[i].len - 1)]] = 1;
}
}
}
int ansA = n - accumulate(a + 1,a + 1 + n, 0);
int ansB = m - accumulate(b + 1,b + 1 + m, 0);
cout << ansA << ' ' << ansB << '
';
}