原题:https://www.luogu.org/problemnew/show/P3763
题解:要把第二条串和第一条串匹配,可以有三个不一样的。首先考虑暴力的方法,一个一个查,就是要找出S,T串的lcp,如果不行的话就要跳过在查后面一段的。那么这道题就转化为如何求出S,T上某一段的lcp。当然有很多办法,最简单的肯定是哈希了。通过哈希可以判断字符串是否是一样的,再配合二分找出最长的相同的长度,接着模拟即可。
#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int N=1e5+10;
const ull D=233;
int cas,n,m;
char S[N],T[N];
ull f[N],g[N],p[N];
int ans;
ull hash(ull *f,int l,int r){//得出[l,r]的哈希值
return f[r]-f[l-1]*p[r-l+1];
}
inline int lcp(int x,int y,int r){//S串的开头,T串的开头
int l=1;//求最长匹配的长度
while(l<=r){
int mid=(l+r)>>1;
if( hash(f,x,x+mid-1)==hash(g,y,y+mid-1) ) l=mid+1;
else r=mid-1;
}
return l-1;
}
bool check(int x){
int y=1,t=0;int r=m+x-1;
for(int i=1;i<=3;i++){
t=lcp(x,y,m-y+1);
x+=t+1;y+=t+1;
if(y>m) return 1;
}
return hash(f,x,r)==hash(g,y,m);
}
int main(){
//freopen("dna.in","r",stdin);
scanf("%d",&cas);
p[0]=1;
for(int i=1;i<=1e5;i++) p[i]=p[i-1]*D;
while(cas--){
scanf("%s%s",S+1,T+1);
n=strlen(S+1);m=strlen(T+1);
if(m>n) {
printf("0\n");continue;
}
f[0]=g[0]=0;
for(int i=1;i<=n;i++) f[i]=f[i-1]*D+S[i];
for(int i=1;i<=m;i++) g[i]=g[i-1]*D+T[i];
ans=0;
for(int i=1;i<=(n-m)+1;i++){
if(check(i)) ans++;
}
printf("%d\n",ans);
}
return 0;
}

本文介绍了解决洛谷P3763题目的方法,使用哈希和二分查找技巧来高效计算两字符串的最长公共前缀,特别适用于解决允许一定错误匹配的字符串匹配问题。
399

被折叠的 条评论
为什么被折叠?



