1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 using namespace std; 6 typedef unsigned long long ull; 7 const int N=100005,p=131;//p进制 hash 8 int T,n,ans,len1,len2; 9 ull f[N],key1[N],key2[N]; 10 char s1[N],s2[N]; 11 void init(){//字符串hash 12 memset(key1,0,sizeof(key1));//可以通过对二分和判定答案时边界的控制避免每次memset的耗时 13 memset(key2,0,sizeof(key2)); 14 for(int i=1;i<=len1;++i){ 15 key1[i]=key1[i-1]*p+(ull)s1[i]; 16 } 17 for(int i=1;i<=len2;++i){ 18 key2[i]=key2[i-1]*p+(ull)s2[i]; 19 } 20 } 21 ull query(int flag,int pos1,int pos2){//查询两个字符串中pos1到pos2的hash值 22 if(flag==1) return key1[pos2]-key1[pos1-1]*f[pos2-pos1+1]; 23 else return key2[pos2]-key2[pos1-1]*f[pos2-pos1+1]; 24 } 25 int lcp(int pos1,int pos2){//二分+hash求s1串中以pos1位置开始和s2串中以pos2位置开始的lcp 26 int l=0,r=min(len1,len2);//r设的较大 貌似可以通过计算传入r 可以避免每次求hash值时memset的时间 27 while(l<r){ 28 int mid=(l+r+1)>>1;//丑陋的二分写法... 29 if(mid>0&&query(1,pos1,pos1+mid-1)==query(2,pos2,pos2+mid-1)) l=mid; 30 else r=mid-1; 31 } 32 return l; 33 } 34 bool check(int pos){ 35 int cnt=0,pos2=1,t; 36 while(cnt<3){//跳三次还不同说明三处以上不同 37 t=lcp(pos,pos2);//lcp 38 pos+=t+1;//这一位不同 两个指针跳到lcp后一位 39 pos2+=t+1; 40 if(pos2>len2) return true; 41 ++cnt; 42 } 43 t=lcp(pos,pos2);//最后判断一下 可能跳三次以后到达s2最后一位 恰巧相等 44 pos+=t,pos2+=t; 45 return pos2>len2; 46 } 47 int main(){ 48 f[0]=1; 49 for(int i=1;i<=N;++i) f[i]=f[i-1]*p;//预处理p的幂 减少计算耗时 50 scanf("%d",&T); 51 while(T--){ 52 scanf("%s",s1+1); 53 scanf("%s",s2+1); 54 len1=strlen(s1+1),len2=strlen(s2+1); 55 if(len1<len2) {//貌似不用解释了??? 56 puts("0"); 57 continue; 58 } 59 init();//hash 预处理 60 ans=0; 61 for(int i=1;i<=len1-len2+1;++i)//枚举每一位作为起点 62 if(check(i)) ++ans; 63 printf("%d\n",ans); 64 } 65 return 0; 66 }
原文:https://www.cnblogs.com/yu-xing/p/10352000.html