1. 程式人生 > 實用技巧 >迴圈同構字串 字串雜湊

迴圈同構字串 字串雜湊

題目

白兔的字串(https://ac.nowcoder.com/acm/problem/15253)

題目描述

白兔有一個字串T。白雲有若干個字串S1,S2..Sn。
白兔想知道,對於白雲的每一個字串,它有多少個子串是和T迴圈同構的。
提示:對於一個字串a,每次把a的第一個字元移動到最後一個,如果操作若干次後能夠得到字串b,則a和b迴圈同構。
所有字元都是小寫英文字母

輸入描述:

第一行一個字串T(|T|<=10^6)
第二行一個正整數n (n<=1000)
接下來n行為S1~Sn (|S1|+|S2|+…+|Sn|<=10 ^ 7),max(|S1|,|S2|,|S3|,|S4|,..|Sn|)<=10 ^ 6

輸出描述:

輸出n行表示每個串的答案

示例1

輸入
abab
2
abababab
ababcbaba
輸出
5
2

思路

迴圈同構,我們吧T環拆鏈,然後儲存所有的迴圈同構字串字串雜湊就可以了。
對於查詢查詢長度為|T|的雜湊值的是否存在就可以了。
坑點:要自然溢位才能A。

#include <bits/stdc++.h>
#define uLL unsigned long long
#define LL long long
using namespace std;

const int maxn=2000005;
struct Hash_char {
    uLL base=131;
    uLL p[maxn], g[maxn];
    void getp() {
        p[0]=1;
        for(int i=1; i<maxn; i++) {
            p[i]=p[i-1]*base;
        }
    }
    uLL Hash(char s[]) {
        int len=strlen(s+1);
        g[0]=0, g[1]=s[1];
        for(int i=2; i<=len; i++) {
            g[i]=(g[i-1]*base+s[i]);
        }
        return g[len];
    }
    uLL getLR(int l, int r) { //得到s[l]-s[r]的hash值
        uLL ans=(g[r]-g[l-1]*p[r-l+1]);
        return ans;
    }
} hc, hd;

struct HashMap { //拉鍊法hash表
    static const int MXSZ = 1e7 + 100; //元素總數 查詢也會建立元素 能開大就開大
    static const int MOD = 1e6 + 3; //1e3+9 1e4+7 1e6+3 1e7+19 1e8+7
    struct node {
        uLL key, val;
        int nxt;
    } elem[MXSZ];
    int head[MOD], tot;
    void init() { //注意初始化!!!
        tot = 0;
        memset(head, -1, sizeof(head));
    }
    bool count(uLL key){
        int k = key % MOD;
        for (int i = head[k]; ~i; i = elem[i].nxt)
            if (elem[i].key == key)
                return 1;
        return 0;
    }
    uLL& operator [] (uLL key) {
        int k = key % MOD; //取模位置
        for (int i = head[k]; ~i; i = elem[i].nxt)
            if (elem[i].key == key) //key相等
                return elem[i].val; //返回val引用
        elem[tot].key = key, elem[tot].nxt = head[k], head[k] = tot; //新建項 將原有的接在當前後並記錄當前
        return elem[tot++].val = 0; //清空值並返回引用
    }
}mp;

char s[maxn];
int main() {

    hc.getp(); hd.getp(); mp.init();
    scanf("%s", s+1);
    int N=strlen(s+1);
    for(int i=1; i<=N; i++) s[N+i]=s[i];
    hc.Hash(s);
    for(int i=1; i<=N; i++){
        mp[hc.getLR(i, i+N-1)]=1;
    }

    int t;
    scanf("%d", &t);
    while(t--) {

        scanf("%s", s+1);
        int len=strlen(s+1);
        if(len<N){
            printf("0\n"); continue;
        }
        hd.Hash(s);
        int ans=0;
        for(int i=1; i<=len-N+1; i++){
            uLL res=hd.getLR(i, i+N-1);
            if(mp.count(res)){
                ans++;
            }
        }
        printf("%d\n", ans);
    }

    return 0;
}