标签:
传送门:Justice String
题意:有两个串A,B,问是否存在A的一个子串S,S和B的长度相等,最多有2个字符不同。如果有多个,输出其实下标最小S的下标,没有输出-1。
分析:从A每个位置开始找最长公共前缀,如果最长公共前缀长度不大于lenb,继续从下一次位置开始找,至多找两次,如果一直找不到就算不存在。
#include <cstdio> #include <cstring> #include <string> #include <queue> #include <cmath> #include <algorithm> #define LL long long #define N 100010 using namespace std; const LL mod=1000000007ll; const LL SEED=131; char a[N],b[N]; int lena,lenb; unsigned LL hha[N],hhb[N]; unsigned LL p[N]; void init() { hha[0]=a[0]; hhb[0]=b[0]; for(int i=1;i<lena;i++) { hha[i]=hha[i-1]*SEED+a[i]; } for(int i=1;i<lenb;i++) { hhb[i]=hhb[i-1]*SEED+b[i]; } } LL calc(int x,int len,unsigned LL f[]) { return f[x+len-1]-f[x-1]*p[len]; } int lcp(int pa,int pb) { int l=0,r=lenb-pb,ans; while(l<=r) { int m=(l+r)>>1; if(calc(pa,m,hha)==calc(pb,m,hhb)) l=m+1,ans=m; else r=m-1; } return ans; } int main() { int T,cas=1; p[0]=1ll; for(int i=1;i<N;i++)p[i]=p[i-1]*SEED; scanf("%d",&T); while(T--) { scanf("%s%s",a,b); lena=strlen(a); lenb=strlen(b); init(); int ans=-1; for(int i=0;i<=lena-lenb;i++) { int num=0; num+=lcp(i+num,num); if(num>=lenb) { ans=i;break; } num++; if(num>=lenb) { ans=i;break; } num+=lcp(i+num,num); if(num>=lenb) { ans=i;break; } num++; if(num>=lenb) { ans=i;break; } num+=lcp(i+num,num); if(num>=lenb) { ans=i;break; } } printf("Case #%d: %d\n",cas++,ans); } }
标签:
原文地址:http://www.cnblogs.com/lienus/p/4389953.html