字符串K次失配匹配
如果在正常的字符串匹配的基础上,如果我们加入可以有 \(K\) 个地方不一样该怎么做?
有一道这个问题的弱化,这篇文章记录一下这道题:P3763 [TJOI2017] DNA
这到题是允许有 3 个以下地方不一样,但不影响这种问题的思路。
就是正常的二分哈希。
我们记录两个串的哈希,到时候查找区间的哈希直接求就行了。
枚举每一个起始位置进行二分到最后一个匹配的位置,判断是否要使用机会。
这个是 \(O(nklogn)\) 的。
代码↓
点击查看代码
#include <bits/stdc++.h>
#define ull unsigned long long
using namespace std;
namespace BaiBaiShaFeng{
const int MN=1e5+115;
const int P=113;
string s_0, s;
int n, m, ans=0;
ull hashed0[MN], p[MN], h[MN];
void Read(){
cin>>s_0>>s; p[0]=1; ans=0;
n=s_0.size(); m=s.size();
for(int i=1; i<=n; ++i) p[i]=(p[i-1]*P);
s_0=' '+s_0; s=' '+s;
}
void Pre(){
for(int i=1; i<=n; ++i)
hashed0[i]=hashed0[i-1]*P+(s_0[i]-'A');
for(int i=1; i<=m; ++i)
h[i]=h[i-1]*P+(s[i]-'A');
}
int get0(int l, int r){
return hashed0[r]-hashed0[l-1]*p[r-l+1];
}
int get1(int l, int r){
return h[r]-h[l-1]*p[r-l+1];
}
bool Check(int s0l, int s0r, int sl, int sr){
if(s0l>n||s0r>n||sl>m||sr>m) return false;
return get0(s0l, s0r)==get1(sl,sr);
}
void solve(){
Read(); Pre();
for(int st=1; st<=n-m+1; ++st){
int pos=1;//当前匹配的位置
int pos0=st;
int cnt=0, valid=false;
while(pos<=m){
if(pos0>n){
valid=true;
break;
}
int l=0, r=min(m-pos+1,n-pos0+1), res=0;
while(l<=r){
int mid=(l+r)>>1;
if(Check(pos0,pos0+mid-1,pos,pos+mid-1)){
res=mid; l=mid+1;
}else{
r=mid-1;
}
}
pos+=res; pos0+=res;
if(pos<=m){
cnt++;
if(cnt>3){
valid=true;
break;
}
pos++; pos0++;
}
}
if(!valid&&cnt<=3){
ans++;
}
}
cout<<ans<<'\n';
}
}
int main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T=1; cin>>T;
while(T--){
BaiBaiShaFeng::solve();
}
return 0;
}

浙公网安备 33010602011771号