PIPI的字符串问题Ⅵ

    PIPI发现不少字符串是相似的,相似是指长度相同,且如果短字符串中两个位置的字符相同则在长字符串的子串中的对应位置也相同,如果短字符串中两个位置的字符不同则在长字符串的子串中的对应位置也不同,比如:abcc和xyzz就是相似的。现在PIPI有一个短字符串S,一个长字符串A,他想知道在这个长字符串中有几个子串与短字符串相似,不同位置的相同子串为不同。

    这题挺巧妙的,5e6的数据范围很容易超时,必须用O(n)的算法。很自然的想到字符串哈希,关键就是编码方法,怎样凸显位置的重要性。后来想到了不用原字符串来哈希,

用一个类似next数组的数组来方法,这个数组的每个元素等于前一个同样字母与当前字母的距离,没有就是0,如abacba对应数组为0 0 2 0 3 3。

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
ull base = 2333;
void pr(vector<int>a){
    for(int x:a)printf("%d ",x);
    printf("\n");
}
int main(){
    string s,t;
    cin>>s>>t;
    if(s.size()>t.size()){
        puts("0");
        return 0;
    }
    ull hs = 0, ht = 0;
    int i,m=s.size(),n=t.size(),ans=0;
    vector<int>ns(m),nt(n),hou(n);
    unordered_map<char,int>mp;
    vector<ull>p(m,1);
    for(i=1;i<m;++i)p[i] = p[i-1]*base;
    for(i=0;i<m;++i){
        if(!mp.count(s[i]))ns[i] = 0;
        else ns[i] = i-mp[s[i]];
        mp[s[i]] = i;
    }
    mp.clear();
    for(i=0;i<n;++i){
        if(!mp.count(t[i])||i-mp[t[i]]>=m)nt[i] = 0;
        else nt[i] = i-mp[t[i]];
        mp[t[i]] = i;
    }
    mp.clear();
    for(i=n-1;i>=0;--i){
        hou[i] = mp[t[i]];
        mp[t[i]] = i;
    }
    //pr(ns);pr(nt);pr(hou);
    for(i=0;i<m;++i)hs = hs*base+ns[i];
    for(i=0;i<m;++i)ht = ht*base+nt[i];
    if(hs==ht)++ans;
    for(i=m;i<n;++i){ 
        ht = (ht-nt[i-m]*p[m-1])*base+nt[i];
        int j = hou[i-m];
        if(j>i-m&&j<=i){
            ht -= nt[j]*p[i-j];
            nt[j] = 0;
        }
        if(ht==hs)++ans;
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2021-03-08 18:46  材料先知  阅读(69)  评论(0)    收藏  举报