Loading

C -Concatenating Teams (字符串hash)

一个比较关键的地方是, 集合中不存在相同的字符串。

还有就是对字符串按长度从小到大排序, 排序后就简单了很多

对于 \(A\)​​ 集合来说, 对于一个当前串, 可以枚举它的前缀, 看之前是否出现过,如果出现过, 把后半部分存下来

对于 \(B\) 集合来说, 对于一个当前串, 可以枚举它的后缀, 如果之前出现过, 把前半部分存下来

并存下每个 hash 值对应的原来位置

在统计答案的时候,

对于集合 A , 对于一个当前串, 枚举它的前缀, 如果出现过,并且后半部分在 B 中作为差值出现过, 则说明该串和它的前缀串都不是特殊的, 利用之前存下来的 hashpos 的映射, 可以找到这个前缀的位置, 给他们俩都打上标记

对于 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) << '\n';
                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) << '\n';
                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 << '\n';

}
posted @ 2021-09-29 12:08  —O0oO-  阅读(65)  评论(0编辑  收藏  举报