字符串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號