Skip to content

14188: 【原4188】罪恶黑名单

题目

题目描述

author: DS TA 原OJ链接:https://acm.sjtu.edu.cn/OnlineJudge-old/problem/4188

Description

联邦探员Elizabeth Keen得到了联邦探员Elizabeth Keen得到了 一份恐怖分子黑名单, 黑名单上有$N$个名字$S_i$, 每个名字$S_i$由连续的小写字母组成, 中间无空格或其它符号. 她对名字进行研究,试图找出 其中的联系.身为反恐团队中的计算机专家, 你需要回答她的三类问题: 类型1,问题为1 $x$,表示询问名字$S_x$是否在 $1\leqslant i < x$中的$S_i$出现. 若出现,请回答yes,否则请回答no. 类型2,问题为2 $x$ $y$,表示询问名字$S_x$, $S_y$的 最长公共前缀的长度. 类型3,问题为3 $x$ $y$,表示询问名字$S_x$, $S_y​$的 最长公共后缀的长度.

Input Format

第一行包含一个正整数$N$, 表示名字个数. 接下来$N$行,每行给出一个非空字符串, 表示名字$S_i$.保证字符串由连续的 小写字母组成,行前行末以及字符串中间没有空格. 接下来一行包含一个正整数$M$, 表示询问次数. 接下来$M$行,每行给出一个询问, 询问格式是上述三类问题的一种, 即1 $x$或2 $x$ $y$或3 $x$ $y$.

Output Format

输出$M$行,第$i$行输出第$i$个询问的答案.

Sample Input

2
goodluck
goodluck
1
1 1

Sample Output

no

Neight99's solution

#include <iostream>
#include <string>

typedef unsigned long long ull;
typedef long long ll;

using namespace std;

const int maxN = 1e5 + 10;
string str[maxN];
int preHashpos[maxN] = {0}, sufHashpos[maxN] = {0};
ull strHash[maxN], preHash1[maxN] = {0}, sufHash1[maxN] = {0};

ull calHash(string str, int l, int r) {
    ull ans = 0;
    for (int i = l; i < r; i++) {
        ans = 131 * ans + (str[i] - 'a' + 1);
    }
    return ans;
}

void preHash(string str, ull *preHash) {
    preHash[0] = str[0] - 'a' + 1;
    for (int i = 1; i < str.length(); i++) {
        preHash[i] = 131 * preHash[i - 1] + (str[i] - 'a' + 1);
    }
}

void sufHash(string str, ull *preHash) {
    int len = str.length();
    preHash[0] = str[len - 1] - 'a' + 1;
    for (int i = 1; i < len; i++) {
        preHash[i] = 131 * preHash[i - 1] + (str[len - i - 1] - 'a' + 1);
    }
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    int N, M, order, x, y;

    cin >> N;
    str[0] = "";
    for (int i = 1; i <= N; i++) {
        cin >> str[i];
        strHash[i] = calHash(str[i], 0, str[i].length());
        preHashpos[i] = preHashpos[i - 1] + str[i - 1].length();
        sufHashpos[i] = sufHashpos[i - 1] + str[i - 1].length();
        preHash(str[i], &preHash1[preHashpos[i]]);
        sufHash(str[i], &sufHash1[sufHashpos[i]]);
    }

    cin >> M;
    for (int i = 0; i < M; i++) {
        cin >> order;
        switch (order) {
            case 1: {
                cin >> x;
                bool flag = 0;
                for (int i = 1; i < x; i++) {
                    if (strHash[i] == strHash[x]) {
                        flag = 1;
                        break;
                    }
                }
                if (flag) {
                    cout << "yes" << '\n';
                } else {
                    cout << "no" << '\n';
                }
                break;
            }
            case 2: {
                cin >> x >> y;
                int len1 = str[x].length(), len2 = str[y].length(),
                    len3 = len1 < len2 ? len1 : len2;
                int l = 0, r = len3 - 1, ans;
                ull *temp1 = &preHash1[preHashpos[x]],
                    *temp2 = &preHash1[preHashpos[y]];
                while (l <= r) {
                    int mid = (l + r) >> 1;
                    if (temp1[mid] == temp2[mid]) {
                        ans = mid + 1;
                        l = mid + 1;
                    } else {
                        r = mid - 1;
                    }
                }
                cout << ans << '\n';
                break;
            }
            case 3: {
                cin >> x >> y;
                int len1 = str[x].length(), len2 = str[y].length(),
                    len3 = len1 < len2 ? len1 : len2;
                int l = 0, r = len3 - 1, ans;
                ull *temp1 = &sufHash1[sufHashpos[x]],
                    *temp2 = &sufHash1[sufHashpos[y]];
                while (l <= r) {
                    int mid = (l + r) >> 1;
                    if (temp1[mid] == temp2[mid]) {
                        ans = mid + 1;
                        l = mid + 1;
                    } else {
                        r = mid - 1;
                    }
                }
                cout << ans << '\n';
                break;
            }
        }
    }
    return 0;
}

victrid's solution

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int
    total;

unsigned long long
    len[1000005]   = {0},
    fhash[1000005] = {0},
    bhash[1000005] = {0},
    shash[1000005] = {0};

char
    buffer[1000005];

int main() {
    scanf("%d", &total);
    for (int i = 1; i <= total; i++) {
        scanf("%s", buffer);
        int s             = strlen(buffer);
        len[i]            = s + len[i - 1];
        fhash[len[i - 1]] = buffer[0];
        bhash[len[i] - 1] = buffer[s - 1];
        for (int j = 1; j < s; j++) {
            //...Hash number...
            fhash[len[i - 1] + j] = fhash[len[i - 1] + j - 1] * 1313 + buffer[j];
            bhash[len[i] - 1 - j] = bhash[len[i] - j] * 1313 + buffer[s - 1 - j];
        }
        shash[i] = fhash[len[i] - 1];
    }
    int times;
    scanf("%d", &times);
    for (int f = 0; f < times; f++) {
        int pg, pf, ps;
        scanf("%d", &ps);
        switch (ps) {
        case 1: {
            bool bf = false;
            scanf("%d", &pf);
            for (int i = 1; i < pf; i++) {
                if (shash[i] == shash[pf]) {
                    bf = true;
                    break;
                }
            }
            printf(bf ? "yes\n" : "no\n");
            break;
        }
        case 2: {
            scanf("%d %d", &pg, &pf);
            int szv = min(len[pg] - len[pg - 1], len[pf] - len[pf - 1]), i = 0;
            for (; i < szv; i++) {
                if (fhash[len[pg - 1] + i] != fhash[len[pf - 1] + i])
                    break;
            }
            printf("%d\n", i);
            break;
        }
        case 3: {
            scanf("%d %d", &pg, &pf);
            int szv = min(len[pg] - len[pg - 1], len[pf] - len[pf - 1]), i = 0;
            for (; i < szv; i++) {
                if (bhash[len[pg] - i - 1] != bhash[len[pf] - i - 1])
                    break;
            }
            printf("%d\n", i);
            break;
        }
        }
    }
    return 0;
}

zqy2018's solution

/*
    Hint: use SAM and hash (or SA?)
*/
#include <bits/stdc++.h>
#define INF 2000000000
#define M 100007ull
using namespace std;
typedef unsigned long long ull;
int read(){
    int f = 1, x = 0;
    char c = getchar();
    while(c < '0' || c > '9'){if(c == '-') f = -f; c = getchar();}
    while(c >= '0' && c <= '9')x = x * 10 + c - '0', c = getchar();
    return f * x; 
}
struct SAM{
    int len[300005], link[300005], to[300005][27];
    int last, D;
    int Sigma;
    SAM(int sigma){
        last = D = 0;
        Sigma = sigma;
        len[0] = 0, link[0] = -1;
        for (int i = 0; i < Sigma; ++i)
            to[0][i] = -1;
    }
    int create_node(){
        int res = ++D;
        link[res] = -1;
        for (int i = 0; i < Sigma; ++i)
            to[res][i] = -1;
        return res;
    }
    int copy_node(int src){
        int res = ++D;
        link[res] = link[src];
        for (int i = 0; i < Sigma; ++i)
            to[res][i] = to[src][i];
        return res;
    }
    inline int get_cid(char c){
        return (c == '#' ? 26: c - 'a');
    }
    void insert(char c){
        int cid = get_cid(c);
        int cur = create_node();
        len[cur] = len[last] + 1;
        int p = last;
        while (p != -1 && to[p][cid] == -1){
            to[p][cid] = cur;
            p = link[p];
        }
        if (p == -1){
            link[cur] = 0;
        }else {
            int q = to[p][cid];
            if (len[p] + 1 == len[q]){
                link[cur] = q;
            }else {
                int clone = copy_node(q);
                len[clone] = len[p] + 1;
                link[cur] = link[q] = clone;
                while (p != -1 && to[p][cid] == q){
                    to[p][cid] = clone;
                    p = link[p];
                }
            }
        }
        last = cur;
    }
    bool check(const string& s){
        int cur = 0, l = s.length();
        for (int i = 0; i < l; ++i){
            cur = to[cur][get_cid(s[i])];
            if (cur == -1) return false;
        }
        return true;
    }
    bool check(char* s, int l){
        int cur = 0;
        for (int i = 0; i < l; ++i){
            cur = to[cur][get_cid(s[i])];
            if (cur == -1) return false;
        }
        return true;
    }
};
SAM sam(27);
int n;
vector<vector<ull> > hsh_pre, hsh_suf;
bool ans[50005] = {0};
void init(){
    ios::sync_with_stdio(false);
    cin >> n;
    for (int i = 0; i < n; ++i){
        string s;
        cin >> s;
        ans[i] = sam.check(s);
        for (char c: s)
            sam.insert(c);
        sam.insert('#');

        hsh_pre.push_back(vector<ull>());
        vector<ull>& v1 = hsh_pre.back();
        v1.push_back(0);
        ull lst = 0;
        for (char c: s)
            lst = lst * M + c - 'a', 
            v1.push_back(lst);

        hsh_suf.push_back(vector<ull>());
        vector<ull>& v2 = hsh_suf.back();
        v2.push_back(0);
        lst = 0;
        int l = s.length();
        for (int i = l - 1; i >= 0; --i)
            lst = lst * M + s[i] - 'a', 
            v2.push_back(lst);
    }
}
int lcp(vector<ull>& v1, vector<ull>& v2){
    int l = 0, r = max(v1.size(), v2.size());
    --r;
    while (r > l){
        int mid = (l + r + 1) >> 1;
        if (v1[mid] == v2[mid])
            l = mid;
        else r = mid - 1;
    }
    return l;
}
void solve(){
    int q;
    cin >> q;
    while (q--){
        int opr;
        cin >> opr;
        if (opr == 1){
            int t;
            cin >> t;
            printf("%s\n", (ans[t - 1] ? "yes": "no"));
        }
        if (opr == 2){
            int x, y;
            cin >> x >> y;
            printf("%d\n", lcp(hsh_pre[x - 1], hsh_pre[y - 1]));
        }
        if (opr == 3){
            int x, y;
            cin >> x >> y;
            printf("%d\n", lcp(hsh_suf[x - 1], hsh_suf[y - 1]));
        }
    }
}
int main(){
    init();
    solve();
    return 0;
}