1.KMP算法
这个博客写的不错:http://www.cnblogs.com/SYCstudio/p/7194315.html
模板:
next数组的求解,那个循环本质就是如果相同前后缀不能加上该位置成就该位置的next数组就一直找相同前后缀的相同前后缀。
求解前缀数组F(也叫next数组):
for (int i=1;i<m;i++) { int j=F[i-1]; while ((B[j+1]!=B[i])&&(j>=0)) j=F[j]; if (B[j+1]==B[i]) F[i]=j+1; else F[i]=-1; }
利用F数组寻找匹配,这里我们是每找到一个匹配就输出其开始的位置:
while (i<n) { if (A[i]==B[j]) { i++; j++; if (j==m) { printf("%d ",i-m+1); j=F[j-1]+1; } } else { if (j==0) i++; else j=F[j-1]+1; } }
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define pb push_back #define mem(a,b) memset((a),(b),sizeof(a)) const int N=1e3+5; int f[N]={-1}; char a[N*N]; char b[N]; int main() { /*ios::sync_with_stdio(false); cin.tie(0);*/ scanf("%s",a); scanf("%s",b); int m=strlen(b); int n=strlen(a); for(int i=1;i<m;i++) { int j=f[i-1]; while(b[j+1]!=b[i]&&j>=0)j=f[j]; if(b[j+1]==b[i])f[i]=j+1; else f[i]=-1; } int i=0,j=0; while(i<n) { if(a[i]==b[j]) { i++; j++; if(j==m) { printf("%d ",i-m+1); j=f[j-1]+1; } } else { if(j==0)i++; else j=f[j-1]+1; } } for(int i=0;i<m;i++) { printf("%d",f[i]+1); if(i!=m-1)printf(" "); else printf(" "); } return 0; }
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define pb push_back #define mem(a,b) memset((a),(b),sizeof(a)) const int N=1e6+5; const int M=1e4+5; int f[M]={-1}; int a[N]; int b[M]; int main() { /*ios::sync_with_stdio(false); cin.tie(0);*/ int t; scanf("%d",&t); while(t--) { int n,m; scanf("%d%d",&n,&m); for(int i=0;i<n;i++)scanf("%d",&a[i]); for(int i=0;i<m;i++)scanf("%d",&b[i]); for(int i=1;i<m;i++) { int j=f[i-1]; while(b[j+1]!=b[i]&&j>=0)j=f[j]; if(b[j+1]==b[i])f[i]=j+1; else f[i]=-1; } int i=0,j=0; bool flag=true; while(i<n) { if(a[i]==b[j]) { i++; j++; if(j==m) { printf("%d ",i-m+1); flag=false; break; } } else { if(j==0)i++; else j=f[j-1]+1; } } if(flag)printf("-1 "); } return 0; }
用next数组求解最小循环节。
代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define ll long long #define pb push_back #define mem(a,b) memset((a),(b),sizeof(a)) const int N=1e6+5; int f[N]={-1}; char s[N]; int main() { /*ios::sync_with_stdio(false); cin.tie(0);*/ while(scanf("%s",s)!=EOF) { if(s[0]=='.')break; int m=strlen(s); for(int i=1;i<m;i++) { int j=f[i-1]; while(s[j+1]!=s[i]&&j>=0)j=f[j]; if(s[j+1]==s[i])f[i]=j+1; else f[i]=-1; } int t=m-(f[m-1]+1); if(m%t)t=m;//如果不整出,那么不存在最小循环节,或者说最小循环节就是字符串本身 printf("%d ",m/t); } return 0; }
例题4:POJ 1961 Period
求每一段的最小循环节。
代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define ll long long #define pb push_back #define mem(a,b) memset((a),(b),sizeof(a)) const int N=1e6+5; int f[N]={-1}; char s[N]; int main() { /*ios::sync_with_stdio(false); cin.tie(0);*/ int n; int c=0; while(scanf("%d",&n)!=EOF&&n) { scanf("%s",s); c++; printf("Test case #%d ",c); int m=strlen(s); for(int i=1;i<m;i++) { int j=f[i-1]; while(s[j+1]!=s[i]&&j>=0)j=f[j]; if(s[j+1]==s[i])f[i]=j+1; else f[i]=-1; int t=i-f[i]; if((i+1)%t==0&&(i+1)/t>1)printf("%d %d ",i+1,(i+1)/t); } printf(" "); } return 0; }
例题5: 471D - MUH and Cube Walls
对差值进行匹配
#include<bits/stdc++.h> using namespace std; #define ll long long #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) const int N=2e5+5; int F[N]={-1},A[N],B[N]; int main(){ ios::sync_with_stdio(false); cin.tie(0); int n,m; cin>>n>>m; for(int i=0;i<n;i++)cin>>A[i]; for(int i=n-1;i>=1;i--)A[i]=A[i]-A[i-1]; A[0]=0; for(int i=0;i<m;i++)cin>>B[i]; for(int i=m-1;i>=1;i--)B[i]=B[i]-B[i-1]; if(m==1){ cout<<n<<endl; return 0; } for(int i=1;i<m;i++)B[i-1]=B[i]; m--; for(int i=1;i<m;i++) { int j=F[i-1]; while(B[j+1]!=B[i]&&j>=0)j=F[j]; if(B[j+1]==B[i])F[i]=j+1; else F[i]=-1; } int cnt=0; /*for(int i=0;i<n;i++)cout<<A[i]<<' '; cout<<endl; for(int i=0;i<m;i++)cout<<B[i]<<' '; cout<<endl; for(int i=0;i<m;i++)cout<<F[i]<<' '; cout<<endl;*/ int i=1,j=0; while (i<n) { if (A[i]==B[j]) { i++; j++; if (j==m) { cnt++; j=F[j-1]+1; } } else { if (j==0) i++; else j=F[j-1]+1; } //cout<<i<<' '<<j<<endl; } cout<<cnt<<endl; return 0; }
2.exkmp算法
https://blog.csdn.net/dyx404514/article/details/41831947
模板:
const int N = 1e6 + 5; int nxt[N], ex[N]; void GETNEXT(char *str) { int i = 0, j, po, len=strlen(str); nxt[0] = len; while(str[i] == str[i+1] && i+1 < len) i++; nxt[1] = i; po = 1; for(i = 2; i < len; i++) { if(nxt[i-po] + i < nxt[po] + po) nxt[i] = nxt[i-po]; else { j=nxt[po] + po - i; if(j < 0) j = 0; while(i + j < len && str[j] == str[j+i]) j++; nxt[i] = j; po = i; } } } void EXKMP(char *s1,char *s2) { int i = 0, j, po, len = strlen(s1), l2=strlen(s2); GETNEXT(s2); while(s1[i] == s2[i] && i < l2 && i < len) i++; ex[0] = i; po = 0; for(i = 1; i < len; i++) { if(nxt[i-po] + i < ex[po] + po) ex[i]=nxt[i-po]; else { j = ex[po] + po - i; if(j < 0) j = 0; while(i + j < len && j < l2 && s1[j+i] == s2[j]) j++; ex[i] = j; po = i; } } }
HDU 2594 Simpsons’ Hidden Talents
代码:
#pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include<bits/stdc++.h> using namespace std; #define y1 y11 #define fi first #define se second #define pi acos(-1.0) #define LL long long //#define mp make_pair #define pb push_back #define ls rt<<1, l, m #define rs rt<<1|1, m+1, r #define ULL unsigned LL #define pll pair<LL, LL> #define pli pair<LL, int> #define pii pair<int, int> #define piii pair<pii, int> #define pdd pair<double, double> #define mem(a, b) memset(a, b, sizeof(a)) #define debug(x) cerr << #x << " = " << x << " "; #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); //head const int N = 100010; int nxt[N], ex[N]; char s[N], t[N]; void GETNEXT(char *str) { int i = 0, j, po, len = strlen(str); nxt[0] = len; while(str[i] == str[i+1] && i+1 < len) i++; nxt[1] = i; po = 1; for(i = 2; i < len; i++) { if(nxt[i-po] + i < nxt[po] + po) nxt[i] = nxt[i-po]; else { j=nxt[po] + po - i; if(j < 0) j = 0; while(i + j < len && str[j] == str[j+i]) j++; nxt[i] = j; po = i; } } } void EXKMP(char *s1,char *s2) { int i = 0, j, po, len = strlen(s1), l2 = strlen(s2); GETNEXT(s2); while(s1[i] == s2[i] && i < l2 && i < len) i++; ex[0] = i; po = 0; for(i = 1; i < len; i++) { if(nxt[i-po] + i < ex[po] + po) ex[i]=nxt[i-po]; else { j = ex[po] + po - i; if(j < 0) j = 0; while(i + j < len && j < l2 && s1[j+i] == s2[j]) j++; ex[i] = j; po = i; } } } int main() { while(~scanf("%s", &s)) { scanf("%s", &t); EXKMP(t, s); int len = strlen(t), res = 0; for (int i = 0; i < len; ++i) { if(ex[i]+i == len) { res = ex[i]; break; } } for (int i = 0; i < res; ++i) putchar(s[i]); if(res)putchar(' '); printf("%d ", res); } return 0; }
void FFT_match(char *s1,char *s2,int m,int n) { reverse(ss1,ss1+m); for(int i=0;i<m;i++) A[i]=(s1[i]!='*')?(s1[i]-'a'+1):0; for(int i=0;i<n;i++) B[i]=(s2[i]!='*')?(s2[i]-'a'+1):0; for(int i=0;i<len;i++) a[i]=Comp(A[i]*A[i]*A[i],0),b[i]=Comp(B[i],0); FFT(a,len,1);FFT(b,len,1); for(int i=0;i<len;i++) P[i]=P[i]+a[i]*b[i]; for(int i=0;i<len;i++) a[i]=Comp(A[i],0),b[i]=Comp(B[i]*B[i]*B[i],0); FFT(a,len,1);FFT(b,len,1); for(int i=0;i<len;i++) P[i]=P[i]+a[i]*b[i]; for(int i=0;i<len;i++) a[i]=Comp(A[i]*A[i],0),b[i]=Comp(B[i]*B[i],0); FFT(a,len,1);FFT(b,len,1); for(int i=0;i<len;i++) P[i]=P[i]-a[i]*b[i]*Comp(2,0); FFT(P,len,-1); for(int i=m-1;i<n;i++) if(fabs(P[i].r)<=1e-7) printf("%d ",i-m+2); }