牛客競賽——白兔的字符串(字符串hash)

博客學習:https://blog.csdn.net/MyLinChi/article/details/79509455 and https://blog.csdn.net/MyLinChi/article/details/79508112

 題目鏈接:https://ac.nowcoder.com/acm/problem/15253

 一涉及循環字符串就要想到擴展加倍字符串

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#include <map>
#include <queue>
#include <cstdio>
#include <string>
#include <stack>
#include <set>
#define IOS ios::sync_with_stdio(false), cin.tie(0)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1000010;
const int seed=131;
ull hs[N],pw[N];
char T[N<<1],s[N];
vector<ull> v;
//初始化hash權值pw;pw[i]=seed^i;
void init_pw(){
    pw[0]=1;
    for(int i=1;i<N;i++){
        pw[i]=pw[i-1]*seed;
    }
}
//O(1)複雜度子串s[i:j]的hash值(通過hash值的相等判斷兩個子串相等)
ull gethash(int i,int j){
    return hs[j]-hs[i-1]*pw[j-i+1];//自然溢出
}
//查找
bool judge(int i,int j){
    ull x=gethash(i,j);
    int id=lower_bound(v.begin(),v.end(),x)-v.begin();
    if(id==v.size())return false;
    else return v[id]==x;
}
int main()
{
    IOS;
    init_pw();
    cin>>(T+1);
    ll len=strlen(T+1);
    hs[0]=1;
    //加倍模式串
    for(int i=1;i<=len;i++){
        T[i+len]=T[i];
    }
    //計算前綴hash
    for(int i=1;i<=2*len;i++){
        hs[i]=hs[i-1]*seed+T[i];
    }
    //計算子串T[i:i+len-1]的hash值,加入vector
    for(int i=1;i<=len;i++){
        v.push_back(gethash(i,i+len-1));
    }
    sort(v.begin(),v.end());//排序便於後續查找
    int n;
    cin>>n;
    while(n--){
        cin>>(s+1);
        ll lens=strlen(s+1);
        int cnt=0;
        //計算s的前綴hash值
        for(int i=1;i<=lens;i++){
            hs[i]=hs[i-1]*seed+s[i];
        }
        //查找有多少個子串s[i:i+len-1]是否在vector中
        for(int i=1;i+len-1<=lens;i++){
            if(judge(i,i+len-1))cnt++;
        }
        cout<<cnt<<endl;
    }
    getchar();
    getchar();
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章