题解:P11705 「KTSC 2020 R1」字符串查找
fish_love_cat · · 题解
从多倍经验来的但是被卡了,严肃更换做法。
双倍经验。
考虑 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;
}
//「好想见──」
// 好想见他们喔。这句话在几乎要脱口之际被吞了回去。
// 妖精兵切忌吐苦水。
// 目前她还在执行重要的任务。最忌有杂念。
// 缇亚忒如此告诉自己,然后从捧著的行李中拿出小包裹,从面具底下把乾巴巴的饼乾塞到了自己嘴里。
// 啪。咔哩咔哩。
// 不甜。不好吃。