BNU 34990 Justice String (hash+二分求LCP)
思路:枚举第一个字符串的位置,然后枚举最长公共前缀的长度,时间即会下降……
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<queue> #include<set> #include<cmath> #include<bitset> #define mem(a,b) memset(a,b,sizeof(a)) #define lson i<<1,l,mid #define rson i<<1|1,mid+1,r #define llson j<<1,l,mid #define rrson j<<1|1,mid+1,r #define seed 131 #define INF 0x7fffffff #define maxn 200105 typedef long long ll; typedef unsigned long long ull; using namespace std; ull base[maxn],hash1[maxn],hash2[maxn]; int n,m; char s1[maxn],s2[maxn]; int judge(int i,int j) { int l=0,r=m,mid,ans=0; while(l<=r) { mid=(l+r)>>1;//二分最长公共前缀 if(i+mid-1>n||j+mid-1>m) { r=mid-1; continue; } ull a=hash1[i+mid-1]-hash1[i-1]*base[mid]; ull b=hash2[j+mid-1]-hash2[j-1]*base[mid]; if(a==b) l=mid+1,ans=mid; else r=mid-1; } return ans; } int main() { freopen("1.txt","r",stdin); int i,t,ii=1,flag; scanf("%d",&t); for(i=1,base[0]=1;i<maxn;i++) base[i]=base[i-1]*seed; while(t--) { scanf("%s%s",s1,s2); n=strlen(s1),m=strlen(s2); for(i=1,hash1[0]=0;i<=n;i++) hash1[i]=hash1[i-1]*seed+s1[i-1]-'a'+1; for(i=1,hash2[0]=0;i<=m;i++) hash2[i]=hash2[i-1]*seed+s2[i-1]-'a'+1; for(i=1;i<=n-m+1;i++)//枚举第一个字符串的起始位置 { int j=1,k=i,cnt=0; flag=0; while(k<=n) { int len=judge(k,j);//两个位置的最长公共前缀 k+=len+1; j+=len+1; cnt++; if(cnt==2) { if(j>m||j+judge(k,j)>m) flag=1; break; } if(j>m) {flag=1;break;} } if(flag) break; } if(flag) printf("Case #%d: %d\n",ii++,i-1); else printf("Case #%d: -1\n",ii++); } return 0; }