题解:P11705 「KTSC 2020 R1」字符串查找

· · 题解

从多倍经验来的但是被卡了,严肃更换做法。

双倍经验。

考虑 kmp,字母和种类无关,和同类的距离有关,考虑把一个点的权值设置为前面最近的同类的距离,显然权值完全匹配那么串就同构。

但是有的点前面没有同类,那么这里就会有一个通配符,一样做就好。

注意如果一个点的权值向前跳后对应点在串内,那么是不能和通配符匹配的。

时间复杂度线性。

#include<bits/stdc++.h>
using namespace std;
vector<int>pi(vector<int>s){
    vector<int>ret;
    ret.push_back(0);
    for(int i=1;i<s.size();i++){
        int flc=ret[i-1];
        while(flc&&s[flc]!=s[i]&&(s[flc]&&s[i]||min(s[flc],s[i])<0||s[i]<=flc))
        flc=ret[flc-1];
        if(s[i]==s[flc]||(s[flc]==0||s[i]==0)&&min(s[flc],s[i])>=0&&s[i]>flc)
        ret.push_back(flc+1);
        else ret.push_back(0);
    }
    return ret;
}
vector<int>kmp(vector<int>s,vector<int>t){
    vector<int>flc=t;
    flc.push_back(-114);
    for(int i:s)
    flc.push_back(i);
    vector<int>ret;
    vector<int>p=pi(flc);
    for(int i=0;i<p.size();i++){
        if(p[i]==t.size())
        ret.push_back(i+1-2*t.size());
    }
    return ret;
}
void solve(){
    map<char,int>mp;
    string s,t;
    cin>>s>>t;
    vector<int>v1,v2;
    for(int i=0;i<s.size();i++){
        if(s[i]<='Z')v1.push_back(-(s[i]-'A'+1));
        else if(!mp[s[i]])v1.push_back(0);
        else v1.push_back(i+1-mp[s[i]]);
        mp[s[i]]=i+1;
    }
    mp.clear();
    for(int i=0;i<t.size();i++){
        if(t[i]<='Z')v2.push_back(-(t[i]-'A'+1));
        else if(!mp[t[i]])v2.push_back(0);
        else v2.push_back(i+1-mp[t[i]]);
        mp[t[i]]=i+1;
    }
    cout<<kmp(v1,v2).size()<<'\n';
}
int main(){
    int t;
    cin>>t;
    while(t--)solve();
    return 0;
}
//「好想见──」
// 好想见他们喔。这句话在几乎要脱口之际被吞了回去。

// 妖精兵切忌吐苦水。
// 目前她还在执行重要的任务。最忌有杂念。

// 缇亚忒如此告诉自己,然后从捧著的行李中拿出小包裹,从面具底下把乾巴巴的饼乾塞到了自己嘴里。

// 啪。咔哩咔哩。
// 不甜。不好吃。