KMP
POJ 3461: Oulipo
题意:
求出第一个串在第二个串中的出现次数...
分析:
KMP板子题...
代码:
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 //by NeighThorn 6 using namespace std; 7 //眉眼如初,岁月如故 8 9 const int maxn=1000000+5; 10 11 int cas,lens,lenp,nxt[maxn]; 12 13 char s[maxn],p[maxn]; 14 15 inline void getnxt(void){ 16 nxt[0]=nxt[1]=0;int k; 17 for(int i=1;i<lenp;i++){ 18 k=nxt[i]; 19 while(k&&p[k+1]!=p[i+1]) 20 k=nxt[k]; 21 if(p[k+1]==p[i+1]) 22 nxt[i+1]=k+1; 23 else 24 nxt[i+1]=0; 25 } 26 } 27 28 inline void kmp(void){ 29 int ans=0,posp=1,poss=1; 30 while(poss<=lens){ 31 if(p[posp]==s[poss]) 32 posp++,poss++; 33 else if(posp==1) 34 poss++; 35 else 36 posp=nxt[posp-1]+1; 37 if(posp==lenp+1) 38 ans++,posp=nxt[posp-1]+1; 39 } 40 printf("%d\n",ans); 41 } 42 43 signed main(void){ 44 scanf("%d",&cas); 45 while(cas--){ 46 memset(nxt,0,sizeof(nxt)); 47 scanf("%s%s",p+1,s+1); 48 lenp=strlen(p+1);lens=strlen(s+1); 49 getnxt();kmp(); 50 } 51 return 0; 52 }//Cap ou pas cap. Pas cap.
POJ 2406: Power Strings
题意:
求出每个串的最短循环节出现次数...
分析:
此题两种解法...然而本质上是一样的...
No.1 Hash
对于一个串其前缀A和后缀B相同并且有重叠,并且len%strlen(str-B)==0,那么str-B一定是循环节...所以我们可以用hash水过...
No.2 next数组...
然而更机智的做法是next数组...
代码:
No.1 Hash
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #define int long long 6 using namespace std; 7 const int maxn=1000000+5,MOD=100000007; 8 char str[maxn]; 9 int len,ans; 10 unsigned int hash[maxn],pow[maxn]; 11 signed main(void){ 12 pow[0]=(long long)1; 13 for(int i=1;i<maxn;i++) 14 pow[i]=(pow[i-1]*30)%MOD; 15 while(scanf("%s",str+1)&&str[1]!='.'){ 16 len=strlen(str+1),hash[0]=0,ans=1; 17 for(int i=1;i<=len;i++) 18 hash[i]=(hash[i-1]*30%MOD+str[i]-'a'+1)%MOD; 19 for(int i=1;i<len;i++){ 20 if(len%(len-i)==0){ 21 if(hash[i]%MOD==(hash[len]-hash[len-i]*pow[i]%MOD+MOD)%MOD){ 22 ans=len/(len-i); 23 } 24 } 25 } 26 cout<<ans<<endl; 27 } 28 return 0; 29 }
No.2 next数组
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 //by NeighThorn 6 using namespace std; 7 //眉眼如初,岁月如故 8 9 const int maxn=1000000+5; 10 11 int len,nxt[maxn]; 12 13 char str[maxn]; 14 15 inline void getnxt(void){ 16 nxt[0]=nxt[1]=0;int k; 17 for(int i=1;i<len;i++){ 18 k=nxt[i]; 19 while(k&&str[k+1]!=str[i+1]) 20 k=nxt[k]; 21 if(str[k+1]==str[i+1]) 22 nxt[i+1]=k+1; 23 else 24 nxt[i+1]=0; 25 } 26 } 27 28 signed main(void){ 29 while(scanf("%s",str+1)&&str[1]!='.'){ 30 len=strlen(str+1);getnxt(); 31 if(len%(len-nxt[len])==0) 32 printf("%d\n",len/(len-nxt[len])); 33 else 34 puts("1"); 35 } 36 return 0; 37 }//Cap ou pas cap. Pas cap.
POJ 2752: Seek the Name, Seek the Fame
题意:
输出所有s的合法前缀,合法前缀的定义为前缀等于后缀...
分析:
不断nxt...
代码:
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 //by NeighThorn 6 using namespace std; 7 //眉眼如初,岁月如故 8 9 const int maxn=400000+5; 10 11 int len,tail,nxt[maxn],stk[maxn]; 12 13 char str[maxn]; 14 15 inline void getnxt(void){ 16 nxt[0]=nxt[1]=0;int k; 17 for(int i=1;i<len;i++){ 18 k=nxt[i]; 19 while(k&&str[k+1]!=str[i+1]) 20 k=nxt[k]; 21 if(str[k+1]==str[i+1]) 22 nxt[i+1]=k+1; 23 else 24 nxt[i+1]=0; 25 } 26 } 27 28 signed main(void){ 29 while(scanf("%s",str+1)!=EOF){ 30 len=strlen(str+1);getnxt();tail=0;stk[++tail]=len; 31 while(nxt[len]) 32 stk[++tail]=nxt[len],len=nxt[len]; 33 for(int i=tail;i>=1;i--) 34 printf("%d ",stk[i]); 35 puts(""); 36 } 37 return 0; 38 }//Cap ou pas cap. Pas cap.
POJ 3167: Cow Patterns
题意:
给出两个串,如果a和b匹配当且仅当ab中的每个对应位置的数字rank1和rank2相同,rank1代表当前元素前面小于他的元素个数,rank2代表当前元素前面等于他的元素个数,求出匹配串和模式串的匹配位置(开头位置)
分析:
KMP…裸的KMP…就是计算一下rank就好…
因为数字不会超过25,所以直接暴力求rank就好…
代码:
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 //by NeighThorn 6 using namespace std; 7 const int maxn=100000+5,maxk=25000+5,maxs=25+5; 8 int n,k,s,a[2][maxn],nxt[maxk],num[2][maxn][maxs],vis[maxk]; 9 inline int rank1(int len,int en,int id){ 10 int st=en-len,ans=0; 11 for(int i=1;i<a[id][en];i++) 12 ans+=num[id][en][i]-num[id][st][i]; 13 return ans; 14 } 15 inline int rank2(int len,int en,int id){ 16 return num[id][en][a[id][en]]-num[id][en-len][a[id][en]]; 17 } 18 inline void getnext(void){ 19 nxt[0]=nxt[1]=0;int p; 20 for(int i=1;i<k;i++){ 21 p=nxt[i];int a=rank1(p+1,p+1,1),b=rank1(p+1,i+1,1),c=rank2(p+1,p+1,1),d=rank2(p+1,i+1,1); 22 while(p&&(a!=b||c!=d)) 23 p=nxt[p],a=rank1(p+1,p+1,1),b=rank1(p+1,i+1,1),c=rank2(p+1,p+1,1),d=rank2(p+1,i+1,1); 24 if(rank1(p+1,p+1,1)==rank1(p+1,i+1,1)&&rank2(p+1,p+1,1)==rank2(p+1,i+1,1)) 25 nxt[i+1]=p+1; 26 else 27 nxt[i+1]=0; 28 } 29 } 30 inline void kmp(void){ 31 int posa=1,posb=1,ans=0,stk[maxn]; 32 while(posa<=n){ 33 if(rank1(posb,posa,0)==rank1(posb,posb,1)&&rank2(posb,posa,0)==rank2(posb,posb,1)) 34 posa++,posb++; 35 else if(posb==1) 36 posa++; 37 else 38 posb=nxt[posb-1]+1; 39 if(posb==k+1) 40 stk[++ans]=posa-k,posb=nxt[posb-1]+1; 41 } 42 cout<<ans<<endl; 43 for(int i=1;i<=ans;i++) 44 cout<<stk[i]<<endl; 45 } 46 signed main(void){ 47 scanf("%d%d%d",&n,&k,&s);memset(num,0,sizeof(num)); 48 for(int i=1;i<=n;i++) 49 scanf("%d",&a[0][i]),num[0][i][a[0][i]]=1; 50 memset(vis,0,sizeof(vis)); 51 for(int i=1;i<=n;i++) 52 for(int j=1;j<=s;j++) 53 num[0][i][j]+=num[0][i-1][j]; 54 for(int i=1;i<=k;i++) 55 scanf("%d",&a[1][i]),num[1][i][a[1][i]]=1; 56 for(int i=1;i<=k;i++) 57 for(int j=1;j<=s;j++) 58 num[1][i][j]+=num[1][i-1][j]; 59 getnext();kmp(); 60 return 0; 61 }
By NeighThorn
转载于:.html