循环同构字符串 字符串哈希

题目

白兔的字符串(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;
}
posted @ 2020-12-09 21:04  liweihang  阅读(435)  评论(0编辑  收藏  举报
Live2D