字符串哈希

码题集OJ-好像相等 (matiji.net)

思路:对26个字母单独哈希26*1e5,然后单独判断每个字母的哈希值是否相同即可。

const unsigned int base=131;
unsigned int p[100005],h[26][100005];
unsigned int n,k;
string str;
void hashInit(){
    p[0]=1;
    for(int i=0;i<26;i++){
        for(int j=1;j<=n;j++){
            p[j]=p[j-1]*base;
            if(str[j]-'a'==i) h[i][j]=h[i][j-1]*base+str[j];
            else h[i][j]=h[i][j-1]*base;
        }
    }
}
BD202419好像相等
https://www.matiji.net/exam/brushquestion/19/4498/F16DA07A4D99E21DFFEF46BD18FF68AD
void solve(){
    cin>>n>>k;
    cin>>str;
    str=" "+str;
    hashInit();
    while(k--){
        vector<char> vct;
        int l1,r1,l2,r2; cin>>l1>>r1>>l2>>r2;
        for(int i=0;i<26;i++){
            if(h[i][r1]-h[i][l1-1]*p[r1-l1+1]!=h[i][r2]-h[i][l2-1]*p[r2-l2+1]) vct.emplace_back('a'+i);
        }
        cout<<vct.size()<<endl;
        for(auto v:vct) cout<<v;
        cout<<endl;
    }
}

E-“好”字符_河南萌新联赛2024第(二)场:南阳理工学院 (nowcoder.com)

思路:同样是单独哈希26个字母。这里因为这里字母可以循环移动,比上一题麻烦一点点,推一下式子计算一下哈希值即可。

const unsigned int base=131;
//const int mod=998244357;
unsigned int p[1000006],h[26][1000006];
unsigned int ha[26],existA[26],existB[26];   用map会导致MLE!!
unordered_map<int,bool> mark;
unsigned int n;
string a,b;
void hashInit(){            用unsigned long long 就不用考虑取mod!!  不然取mod取错就寄
    p[0]=1;
    for(int i=0;i<26;i++){
        int h0=0;
        for(int j=1;j<=n;j++){
            p[j]=p[j-1]*base;
            if(b[j]-'a'==i) h[i][j]=(h[i][j-1]*base+b[j]),existB[i]=1;
            else h[i][j]=(h[i][j-1]*base);

            if(a[j]-'a'==i) h0=(h0*base+a[j]),existA[i]=1;
            else h0=(h0*base);
        }
        ha[i]=h0;
        mark[h0]=1;
    }
}
“好”字符
https://ac.nowcoder.com/acm/contest/87255/E
void solve(){       补E  字符串哈希
    cin>>n>>a>>b;
    a=" "+a,b=" "+b;
    hashInit();
    int ans=0;
    for(int c=0;c<26;c++){
        if(!existA[c]||!existB[c]) continue;
        for(int i=0;i<n;i++){
            if(ha[c]==((h[c][n]-h[c][i]*p[n-i])*p[i]+h[c][i])){
                ans++;
                break;
            }
        }
    }
    cout<<ans;
}

Fixing a Binary String - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:这题因为操作会使字符串翻转,那么可以直接把原始字符串顺/逆都哈希一次,然后计算哈希值即可。切记减的时候不要忘记补上差的base..警钟长鸣!

单哈希:

自然溢出
const ull base=131;
ull p[200005],h[2][200005],h0=0,h1=0;  输入的字符串顺逆都哈希一次
int n,k;
string str,ReStr;
void hashInit(){
    string str0=" ",str1=" ";
    int cnt=0,mark=1;
    p[0]=1,h[0][0]=0,h[1][0]=0;
    for(int i=1;i<=n;i++){
        p[i]=p[i-1]*base;
        h[0][i]=h[0][i-1]*base+str[i];
        h[1][i]=h[1][i-1]*base+ReStr[i];
        if(mark) str0+="0",str1+="1";
        else str0+="1",str1+="0";
        cnt++;
        if(cnt>=k) cnt=0,mark^=1;
    }
    for(int i=1;i<=n;i++){
        h0=h0*base+str0[i];
        h1=h1*base+str1[i];
    }
}
D. Fixing a Binary String
https://www.luogu.com.cn/problem/CF1979D
void solve(){               字符串哈希---------单哈希(自然溢出)
    cin>>n>>k;
    cin>>str;
    ReStr=str,reverse(ReStr.begin(),ReStr.end()),ReStr=" "+ReStr;
    str=" "+str;
    h0=0,h1=0;    初始化
    hashInit();
    for(int i=1;i<=n;i++){
        ull cur=(h[0][n]-h[0][i]*p[n-i])*p[i]+h[1][n]-h[1][n-i]*p[i]; 两个减都少了base
        if(cur==h0||cur==h1){
            cout<<i<<endl;
            return;
        }
    }
    cout<<"-1"<<endl;
}

双哈希(双倍空间):

const ull base=131;
const int baseb=13331;
const int mod=998244353;
ull p[200005],h[2][200005],h0=0,h1=0;
int pp[200005],hh[2][200005],hh0=0,hh1=0;
int n,k;
string str,ReStr;
void hashInit(){
    string str0=" ",str1=" ";
    int cnt=0,mark=1;
    p[0]=1,pp[0]=1;
    for(int i=1;i<=n;i++){
        p[i]=p[i-1]*base;
        h[0][i]=h[0][i-1]*base+str[i];
        h[1][i]=h[1][i-1]*base+ReStr[i];

        pp[i]=pp[i-1]*baseb,pp[i]%=mod;
        hh[0][i]=hh[0][i-1]*baseb+str[i],hh[0][i]%=mod;
        hh[1][i]=hh[1][i-1]*baseb+ReStr[i],hh[1][i]%=mod;

        if(mark) str0+="0",str1+="1";
        else str0+="1",str1+="0";
        cnt++;
        if(cnt>=k) cnt=0,mark^=1;
    }
    for(int i=1;i<=n;i++){
        h0=h0*base+str0[i];
        h1=h1*base+str1[i];

        hh0=hh0*baseb+str0[i],hh0%=mod;
        hh1=hh1*baseb+str1[i],hh1%=mod;
    }
}
D. Fixing a Binary String
https://www.luogu.com.cn/problem/CF1979D
void solve(){               字符串哈希--------------双哈希(自然溢出+mod)
    cin>>n>>k;
    cin>>str;
    ReStr=str,reverse(ReStr.begin(),ReStr.end()),ReStr=" "+ReStr;
    str=" "+str;
    h0=0,h1=0,hh0=0,hh1=0;    初始化
    hashInit();
    for(int i=1;i<=n;i++){
        pair<ull,int> cur;
        cur.first=(h[0][n]-h[0][i]*p[n-i])*p[i]+h[1][n]-h[1][n-i]*p[i];
        cur.second=((hh[0][n]-hh[0][i]*pp[n-i]%mod+mod)%mod*pp[i]%mod+(hh[1][n]-hh[1][n-i]*pp[i]%mod+mod)%mod)%mod;
        if(cur==make_pair(h0,hh0)||cur==make_pair(h1,hh1)){
            cout<<i<<endl;
            return;
        }
    }
    cout<<"-1"<<endl;
}

Problem - 7433 (hdu.edu.cn)循环位移

思路:哈希典题,找子串。unordered_map标记stra的k个哈希值。

const ull base=131;
string stra,strb;
ull ha[1050000],hb[1050000];
ull p[1050000];
int na,nb;
void hashInit(){
    p[0]=1;
    for(int i=1;i<=nb;i++){
        if(i<=na) ha[i]=ha[i-1]*base+stra[i];
        p[i]=p[i-1]*base;
        hb[i]=hb[i-1]*base+strb[i];
    }
}
如果枚举k,遍历strb时间复杂度为na*(nb-na)--TLE
优化,标记stra的k个哈希值,o(nb)遍历strb--ac
循环位移
https://acm.hdu.edu.cn/showproblem.php?pid=7433
和牛客萌新赛的,"好"字符,非常相似
void solve(){
    cin>>stra>>strb;
    na=stra.size(),nb=strb.size();
    stra=" "+stra,strb=" "+strb;
    hashInit();
    ull cnt=0;
    unordered_map<ull,bool> mark;
    for(int k=0;k<na;k++){
        ull cura=(ha[na]-ha[k]*p[na-k])*p[k]+ha[k];
        mark[cura]=1;
    }
    for(int i=na;i<=nb;i++){
        ull curb=hb[i]-hb[i-na]*p[na];
        if(mark[curb]) cnt++;
    }
    cout<<cnt<<endl;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值