(17/34)AC自动机/后缀数组/后缀自动机(施工中)
快补题别再摸鱼了(17/34)
1.AC自动机
#define maxnode 1000010 #define maxsize 26 struct ahocT{ int ch[maxnode][maxsize]; int e[maxnode],fail[maxnode]; int sz; void init(){ sz=1;memset(ch[0],0,sizeof(ch[0]));memset(e,0,sizeof(e));return; } int idx(char c) {return c-'a';} void insert(char *x){ int u=0,len=strlen(x); FOR(i,0,len){ int c=idx(x[i]); if(!ch[u][c]){ memset(ch[sz],0,sizeof(ch[sz])); ch[u][c]=sz++; } u=ch[u][c]; } e[u]++; return; } void build(){ int u; queue<int> q; memset(fail,0,sizeof(fail)); FOR(i,0,26) if(ch[0][i]) q.push(ch[0][i]); while(!q.empty()){ u=q.front();q.pop(); FOR(i,0,26){ if(ch[u][i]) { fail[ch[u][i]]=ch[fail[u]][i]; q.push(ch[u][i]); } else ch[u][i]=ch[fail[u]][i]; } } return; } int query(char *x){ int ans=0,c=0,len=strlen(x); FOR(i,0,len){ c=ch[c][idx(x[i])]; for(int j=c;j&&~e[j];j=fail[j]) ans+=e[j],e[j]=-1; } return ans; } }
模板写法及变式(待更新)
ac自动机的主要考察方向:DP 矩阵转移 图论
HDU 2222
多模式串匹配 模板题
//#define LOCAL #include <cstring> #include <iostream> #include <sstream> #include <fstream> #include <string> #include <vector> #include <deque> #include <queue> #include <stack> #include <set> #include <map> #include <algorithm> #include <functional> #include <utility> #include <bitset> #include <cmath> #include <cstdlib> #include <ctime> #include <cstdio> using namespace std; #define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z)) // X_INIT=0 mem_Macro #define INF 0x3f3f3f3f #define MOD 1000000007 #define FOR(i,j,k) for(int i=j;i<k;i+=1) #define FORD(i,j,k) for(int i=j;i>k;i-=1) #define uLL unsigned long long #define LL long long #define SZ(x) int(x.size()) #define pb push_back #define maxnode 1000010 #define maxsize 26 int n; char x[1000050]; int ch[maxnode][maxsize]; int e[maxnode],fail[maxnode]; int sz; void init(){ sz=1;/*memset(ch[0],0,sizeof(ch[0]));memset(e,0,sizeof(e));*/return; } int idx(char c) {return c-'a';} void insert(char *x){ int u=0,len=strlen(x); FOR(i,0,len){ int c=idx(x[i]); if(!ch[u][c]){ /*memset(ch[sz],0,sizeof(ch[sz]));*/ ch[u][c]=sz++; } u=ch[u][c]; } e[u]++; return; } void build(){ int u; queue<int> q; //memset(fail,0,sizeof(fail)); FOR(i,0,26) if(ch[0][i]) q.push(ch[0][i]); while(!q.empty()){ u=q.front();q.pop(); FOR(i,0,26){ if(ch[u][i]) { fail[ch[u][i]]=ch[fail[u]][i]; q.push(ch[u][i]); } else ch[u][i]=ch[fail[u]][i]; } } return; } int query(char *x){ int ans=0,c=0,len=strlen(x); FOR(i,0,len){ c=ch[c][idx(x[i])]; for(int j=c;j&&~e[j];j=fail[j]) ans+=e[j],e[j]=-1; } return ans; } int main(){ #ifdef LOCAL freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); #endif //ahocT tr; int t; scanf("%d",&t); FOR(i,0,t){ init(); sz=1; scanf("%d",&n); FOR(i,0,n){ scanf("%s",x); insert(x); } build(); scanf("%s",x); printf("%d\n",query(x)); } //system("pause"); #ifdef LOCAL fclose(stdin); fclose(stdout); #endif return 0; }
HDU 2896
多模式串匹配统计,多模板串set处理
//#define LOCAL #include <cstring> #include <iostream> #include <sstream> #include <fstream> #include <string> #include <vector> #include <deque> #include <queue> #include <stack> #include <set> #include <map> #include <algorithm> #include <functional> #include <utility> #include <bitset> #include <cmath> #include <cstdlib> #include <ctime> #include <cstdio> using namespace std; #define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z)) // X_INIT=0 mem_Macro #define INF 0x3f3f3f3f #define MOD 1000000007 #define FOR(i,j,k) for(int i=j;i<k;i+=1) #define FORD(i,j,k) for(int i=j;i>k;i-=1) #define uLL unsigned long long #define LL long long #define SZ(x) int(x.size()) #define pb push_back #define maxnode 100010 #define maxsize 130 int l,n; char x[10010]; struct ahocT{ int ch[maxnode][maxsize]; int e[maxnode],fail[maxnode],vis[maxnode]; int sz; void init(){ sz=1;memset(ch[0],0,sizeof(ch[0]));memset(e,0,sizeof(e));return; } int idx(char c) {return (int)c;} void insert(char *x,int num){ int u=0,len=strlen(x); FOR(i,0,len){ int c=idx(x[i]); if(!ch[u][c]){ memset(ch[sz],0,sizeof(ch[sz])); ch[u][c]=sz++; } u=ch[u][c]; } e[u]=num; return; } void build(){ int u; queue<int> q; memset(fail,0,sizeof(fail)); FOR(i,0,129) if(ch[0][i]) q.push(ch[0][i]); while(!q.empty()){ u=q.front();q.pop(); FOR(i,0,129){ if(ch[u][i]) { fail[ch[u][i]]=ch[fail[u]][i]; q.push(ch[u][i]); } else ch[u][i]=ch[fail[u]][i]; } } return; } int query(char *x,int ii){ int ans=0,c=0,len=strlen(x); memset(vis,0,sizeof(vis)); FOR(i,0,len){ c=ch[c][idx(x[i])]; for(int j=c;j&&~e[j];j=fail[j]) vis[e[j]]++,ans+=e[j]; } if(ans) {printf("web %d:",ii); FOR(j,1,sz) if(e[j]) if(vis[e[j]]) printf(" %d",e[j]); printf("\n");return 1;} else return 0; } }; ahocT xx; int main(){ #ifdef LOCAL freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); #endif scanf("%d",&n); xx.init(); FOR(i,1,n+1){ scanf("%s",x); xx.insert(x,i); } xx.build(); scanf("%d",&n); int l=0; FOR(i,1,n+1){ scanf("%s",x); l+=xx.query(x,i); } printf("total: %d\n",l); //system("pause"); #ifdef LOCAL fclose(stdin); fclose(stdout); #endif return 0; }
HDU 3065
多模式串匹配统计次数
为防止多个模式串重复,一般分配map映射
//#define LOCAL #include <cstring> #include <iostream> #include <sstream> #include <fstream> #include <string> #include <vector> #include <deque> #include <queue> #include <stack> #include <set> #include <map> #include <algorithm> #include <functional> #include <utility> #include <bitset> #include <cmath> #include <cstdlib> #include <ctime> #include <cstdio> using namespace std; #define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z)) // X_INIT=0 mem_Macro #define INF 0x3f3f3f3f #define MOD 1000000007 #define FOR(i,j,k) for(int i=j;i<k;i+=1) #define FORD(i,j,k) for(int i=j;i>k;i-=1) #define uLL unsigned long long #define LL long long #define SZ(x) int(x.size()) #define pb push_back #define maxnode 100010 #define maxsize 130 int l,n; char lx[1010][60]; char xxx[2000010]; struct ahocT{ int ch[maxnode][maxsize]; int e[maxnode],fail[maxnode],vis[maxnode]; int idxx[maxnode]; int sz; void init(){ sz=1;memset(ch[0],0,sizeof(ch[0]));memset(e,0,sizeof(e));return; } int idx(char c) {return (int)c;} void insert(char *x,int num){ int u=0,len=strlen(x); FOR(i,0,len){ int c=idx(x[i]); if(!ch[u][c]){ memset(ch[sz],0,sizeof(ch[sz])); ch[u][c]=sz++; } u=ch[u][c]; } e[u]=num;idxx[num]=u; return; } void build(){ int u; queue<int> q; memset(fail,0,sizeof(fail)); FOR(i,0,129) if(ch[0][i]) q.push(ch[0][i]); while(!q.empty()){ u=q.front();q.pop(); FOR(i,0,129){ if(ch[u][i]) { fail[ch[u][i]]=ch[fail[u]][i]; q.push(ch[u][i]); } else ch[u][i]=ch[fail[u]][i]; } } return; } void query(char *x){ int ans=0,c=0,len=strlen(x); memset(vis,0,sizeof(vis)); FOR(i,0,len){ c=ch[c][idx(x[i])]; for(int j=c;j&&~e[j];j=fail[j]) vis[j]++,ans+=e[j]; } //printf("web %d:",ii); FOR(j,1,n+1){ if(vis[idxx[j]]) printf("%s: %d\n",lx[j],vis[idxx[j]]); } //if(e[j]) if(vis[e[j]]) printf(" %d",e[j]); //printf("\n");return 1;} else return 0; return; } }; ahocT xx; int main(){ #ifdef LOCAL freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); #endif while(scanf("%d",&n)!=EOF){ xx.init(); FOR(i,1,n+1){ scanf("%s",lx[i]); xx.insert(lx[i],i); } xx.build(); //scanf("%d",&n); //int l=0; //FOR(i,1,n+1){ scanf("%s",xxx); xx.query(xxx); //cout<<xxx; //} //printf("total: %d\n",l); } //system("pause"); #ifdef LOCAL fclose(stdin); fclose(stdout); #endif return 0; }
ZOJ 3430
base64转码+多模式串匹配统计
//#define LOCAL #include <cstring> #include <iostream> #include <sstream> #include <fstream> #include <string> #include <vector> #include <deque> #include <queue> #include <stack> #include <set> #include <map> #include <algorithm> #include <functional> #include <utility> #include <bitset> #include <cmath> #include <cstdlib> #include <ctime> #include <cstdio> using namespace std; #define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z)) // X_INIT=0 mem_Macro #define INF 0x3f3f3f3f #define MOD 1000000007 #define FOR(i,j,k) for(int i=j;i<k;i+=1) #define FORD(i,j,k) for(int i=j;i>k;i-=1) #define uLL unsigned long long #define LL long long #define SZ(x) int(x.size()) #define pb push_back #define maxnode 50010 #define maxsize 256 char x[2100]; int xx[4000]; int id(char c) { if(c >= 'A' && c <= 'Z') return c - 'A'; else if(c >= 'a' && c <= 'z') return c - 'a' + 26; else if(c >= '0' && c <= '9') return c - '0' + 52; else if(c == '+') return 62; else return 63; } struct ahocT{ int ch[maxnode][maxsize]; int e[maxnode],fail[maxnode]; int vis[maxnode]; int sz; void init(){ sz=1;memset(ch[0],0,sizeof(ch[0]));memset(e,0,sizeof(e));return; } int idx(int c) {return c;} void insert(int *x,int len){ int u=0;//,len=strlen(x); FOR(i,0,len){ int c=idx(x[i]); if(!ch[u][c]){ memset(ch[sz],0,sizeof(ch[sz])); ch[u][c]=sz++; } u=ch[u][c]; } e[u]++; return; } void build(){ int u; queue<int> q; memset(fail,0,sizeof(fail)); FOR(i,0,256) if(ch[0][i]) q.push(ch[0][i]); while(!q.empty()){ u=q.front();q.pop(); FOR(i,0,256){ if(ch[u][i]) { fail[ch[u][i]]=ch[fail[u]][i]; q.push(ch[u][i]); } else ch[u][i]=ch[fail[u]][i]; } } return; } int query(int *x,int len){ int ans=0,c=0;//len=strlen(x); memset(vis,0,sizeof(vis)); FOR(i,0,len){ c=ch[c][idx(x[i])]; for(int j=c;j&&~e[j];j=fail[j]) if(vis[j]==0) {ans+=e[j],vis[j]=1;} //{ans+=e[j],e[j]=-1;} } return ans; } } tt; int main(){ #ifdef LOCAL freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); #endif int n,m; while(scanf("%d",&n)!=EOF){ tt.init(); //cout<<"**"; FOR(i,0,n){ scanf("%s",x); int len=strlen(x); int cnt=0; while(x[len-1]=='=') len--; for(int j=0;j<len;j+=4){ xx[cnt++]=(id (x[j])<<2|id(x[j+1])>>4);//6 2 if(j+2<len) xx[cnt++]=((id(x[j+1])&0x0f)<<4)|id(x[j+2])>>2;//4 4 if(j+3<len) xx[cnt++]=((id(x[j+2])&0x03)<<6)|id(x[j+3]);//2 6 } /* FOR(j,0,cnt) cout<<xx[j]<<' '; cout<<' '<<endl;*/ tt.insert(xx,cnt); } tt.build(); scanf("%d",&m); FOR(i,0,m){ scanf("%s",x); int len=strlen(x); int cnt=0; while(x[len-1]=='=') len--; for(int j=0;j<len;j+=4){ xx[cnt++]=(id(x[j])<<2|id(x[j+1])>>4);//6 2 if(j+2<len) xx[cnt++]=((id(x[j+1])&0x0f)<<4)|id(x[j+2])>>2;//4 4 if(j+3<len) xx[cnt++]=((id(x[j+2])&0x03)<<6)|id(x[j+3]);//2 6 } /* FOR(j,0,cnt) cout<<xx[j]<<' '; cout<<' '<<endl;*/ printf("%d\n",tt.query(xx,cnt)); } printf("\n"); } //system("pause"); #ifdef LOCAL fclose(stdin); fclose(stdout); #endif return 0; }
POJ 2778
求不出现模式串的定长构造串个数
矩阵快速幂转移fail矩阵 求sigma(fail[0][i])
//#define LOCAL #include <cstring> #include <iostream> #include <sstream> #include <fstream> #include <string> #include <vector> #include <deque> #include <queue> #include <stack> #include <set> #include <map> #include <algorithm> #include <functional> #include <utility> #include <bitset> #include <cmath> #include <cstdlib> #include <ctime> #include <cstdio> using namespace std; #define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z)) // X_INIT=0 mem_Macro #define INF 0x3f3f3f3f #define MOD 1000000007 #define FOR(i,j,k) for(int i=j;i<k;i+=1) #define FORD(i,j,k) for(int i=j;i>k;i-=1) #define uLL unsigned long long #define LL long long #define SZ(x) int(x.size()) #define pb push_back #define maxnode 110 #define maxsize 26 char x[20]; LL dp[101][101]; map<char,int> id; struct ahocT{ int ch[maxnode][maxsize]; int e[maxnode],fail[maxnode]; int sz; void init(){ sz=1;memset(ch[0],0,sizeof(ch[0]));memset(e,0,sizeof(e));return; } int idx(char c) {return id[c];} void insert(char *x){ int u=0,len=strlen(x); FOR(i,0,len){ int c=idx(x[i]); if(!ch[u][c]){ memset(ch[sz],0,sizeof(ch[sz])); ch[u][c]=++sz; } u=ch[u][c]; } e[u]++; return; } void build(){ int u; queue<int> q; memset(fail,0,sizeof(fail)); FOR(i,0,4) if(ch[0][i]) q.push(ch[0][i]); while(!q.empty()){ u=q.front();q.pop(); FOR(i,0,4){ if(ch[u][i]) { fail[ch[u][i]]=ch[fail[u]][i]; q.push(ch[u][i]); if(e[fail[ch[u][i]]]) e[ch[u][i]]=1; } else ch[u][i]=ch[fail[u]][i]; } } return; } int query(char *x){ int ans=0,c=0,len=strlen(x); FOR(i,0,len){ c=ch[c][idx(x[i])]; for(int j=c;j&&~e[j];j=fail[j]) ans+=e[j],e[j]=-1; } return ans; } }tt; /*() void(LL *a,int len,int cc){ LL xx[len+1][len+1],tmp[len+1][len+1],ans[len+1][len+1]; int c=cc; //memset(xx,0,sizeof(xx))拢禄 FOR(i,0,len) FOR(j,0,len) xx[i][j]=a[i][j]; while(c){ if(c&1){ FOR(i,0,len) FOR(j,0,len) FOR(k,0,len) tmp[i][j]+=ans[i][k]*a[k][j]; FOR(i,0,len) FOR(j,0,len) ans[i][j]=tmp[i][j]; } FOR(i,0,len) FOR(j,0,len) FOR(k,0,len) tmp[i][j]+=xx[i][k]*xx[k][j]; FOR(i,0,len) FOR(j,0,len) xx[i][j]=tmp[i][j]; c/=2; } int anss=0; FOR(i,0,len) anss+=ans[0][i]; printf("%lld\n",anss); return; }*/ int main(){ #ifdef LOCAL freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); #endif id['A']=0; id['T']=1; id['G']=2; id['C']=3; int m,n; scanf("%d%d",&m,&n); FOR(i,0,m){ scanf("%s",x); tt.insert(x); } tt.build(); //cout<<tt.sz; int len=tt.sz+1; FOR(i,0,tt.sz+1){ if(!tt.e[i]) FOR(j,0,4) if(!tt.e[tt.ch[i][j]])dp[i][tt.ch[i][j]]++; } /*FOR(i,0,tt.sz+1){ FOR(j,0,tt.sz+1) cout<<dp[i][j]; cout<<endl; }*/ //q_pow(dp,len,m); LL xx[101][101],tmp[101][101],ans[101][101]; int c=n; memset(ans,0,sizeof(ans)); FOR(i,0,len) FOR(j,0,len) xx[i][j]=dp[i][j]; FOR(i,0,len) ans[i][i]=1; while(c){ // cout<<c<<endl; if(c&1){ memset(tmp,0,sizeof(tmp)); FOR(i,0,len) FOR(j,0,len) FOR(k,0,len) tmp[i][j]+=xx[i][k]*ans[k][j],tmp[i][j]%=100000; FOR(i,0,len) FOR(j,0,len) ans[i][j]=tmp[i][j]; } memset(tmp,0,sizeof(tmp)); FOR(i,0,len) FOR(j,0,len) FOR(k,0,len) tmp[i][j]+=xx[i][k]*xx[k][j],tmp[i][j]%=100000; FOR(i,0,len) FOR(j,0,len) xx[i][j]=tmp[i][j]; c>>=1; /* FOR(i,0,len){ FOR(j,0,len) cout<<ans[i][j]; cout<<endl;} */} LL anss=0; FOR(i,0,len) anss+=ans[0][i]; printf("%lld\n",anss%100000); //system("pause"); #ifdef LOCAL fclose(stdin); fclose(stdout); #endif return 0; }
HDU 2243
求出现模式串的不定长构造串个数
构造矩阵A:【fail E】和B:【26 1】
【0 E】 【0 1】
矩阵快速幂转移后求B左上与A右上第一行simga之差
#include <cstring> #include <iostream> #include <sstream> #include <fstream> #include <string> #include <vector> #include <deque> #include <queue> #include <stack> #include <set> #include <map> #include <algorithm> #include <functional> #include <utility> #include <bitset> #include <cmath> #include <cstdlib> #include <ctime> #include <cstdio> using namespace std; #define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z)) // X_INIT=0 mem_Macro #define INF 0x3f3f3f3f #define MOD 1000000007 #define FOR(i,j,k) for(int i=j;i<k;i+=1) #define FORD(i,j,k) for(int i=j;i>k;i-=1) #define uLL unsigned long long #define LL long long #define SZ(x) int(x.size()) #define pb push_back #define maxnode 110 #define maxsize 26 #define N 100 struct Mat{ uLL mat[N][N]; }; Mat operator *(Mat x,Mat y){ Mat c; memset(c.mat,0,sizeof(c.mat)); FOR(k,0,N) FOR(i,0,N){ if(x.mat[i][k]<=0) continue; FOR(j,0,N){ if(y.mat[k][j]<=0) continue; c.mat[i][j]+=x.mat[i][k]*y.mat[k][j]; } } return c; } char x[20]; uLL dp[101][101]; map<char,int> id; struct ahocT{ int ch[maxnode][maxsize]; int e[maxnode],fail[maxnode]; int sz; void init(){ sz=1;memset(ch[0],0,sizeof(ch[0]));memset(e,0,sizeof(e));return; } int idx(char c) {return c-'a';} void insert(char *x){ int u=0,len=strlen(x); FOR(i,0,len){ int c=idx(x[i]); if(!ch[u][c]){ memset(ch[sz],0,sizeof(ch[sz])); ch[u][c]=sz++; } u=ch[u][c]; } e[u]++; return; } void build(){ int u; queue<int> q; memset(fail,0,sizeof(fail)); FOR(i,0,26) if(ch[0][i]) q.push(ch[0][i]); while(!q.empty()){ u=q.front();q.pop(); FOR(i,0,26){ if(ch[u][i]) { fail[ch[u][i]]=ch[fail[u]][i]; q.push(ch[u][i]); if(e[fail[ch[u][i]]]) e[ch[u][i]]=1; } else ch[u][i]=ch[fail[u]][i]; } } return; } int query(char *x){ int ans=0,c=0,len=strlen(x); FOR(i,0,len){ c=ch[c][idx(x[i])]; for(int j=c;j&&~e[j];j=fail[j]) ans+=e[j],e[j]=-1; } return ans; } }tt; Mat qpow(Mat x,int le){ Mat res; memset(res.mat,0,sizeof(res.mat)); int cc=le; FOR(i,0,N) res.mat[i][i]=1; while(cc){ if(cc&1) res=res*x; x=x*x; cc>>=1; } return res; } int main(){ int m,n; while(scanf("%d%d",&m,&n)!=EOF){ tt.init(); FOR(i,0,m){ scanf("%s",x); tt.insert(x); } tt.build(); Mat dp; memset(dp.mat,0,sizeof(dp.mat)); FOR(i,0,tt.sz){ if(tt.e[i]) continue; FOR(j,0,26) if(tt.e[tt.ch[i][j]]==0)dp.mat[i][tt.ch[i][j]]++; } FOR(i,tt.sz,2*tt.sz) dp.mat[i-tt.sz][i]=1; FOR(i,tt.sz,2*tt.sz) dp.mat[i][i]=1;/* FOR(i,0,tt.sz) cout<<tt.e[i]; cout<<tt.sz<<endl; FOR(i,0,2*tt.sz){ FOR(j,0,2*tt.sz) cout<<dp.mat[i][j]<<' '; cout<<endl; }*/dp=qpow(dp,n); uLL ans=0; FOR(i,0,2*tt.sz) ans+=dp.mat[0][i]; ans--; //LL ans=dp.mat[0][tt.sz+1]-1; Mat p; memset(p.mat,0,sizeof(p.mat)); p.mat[0][0]=26;p.mat[0][1]=1;p.mat[1][1]=1; p=qpow(p,n); uLL ans2=p.mat[0][0]+p.mat[0][1]; ans2--; cout<<ans2-ans<<endl; } return 0; }
POJ 1625
求不出现模式串的定长构造串个数的高精度大数
加上大数模板
未写题:
HDU 2825
HDU 2296
HDU 2457
ZOJ 3228
HDU 3341
HDU 3247
HDU 4758
HDU 4511
2.后缀数组
#include <algorithm> #include <cstdio> #include <cstring> #include <iostream> using namespace std; const int N = 1000010; char s[N]; int n, w, sa[N], rk[N << 1], oldrk[N << 1]; // 为了防止访问 rk[i+w] 导致数组越界,开两倍数组。 // 当然也可以在访问前判断是否越界,但直接开两倍数组方便一些。 int main() { int i, p; scanf("%s", s + 1); n = strlen(s + 1); for (i = 1; i <= n; ++i) rk[i] = s[i]; for (w = 1; w < n; w <<= 1) { for (i = 1; i <= n; ++i) sa[i] = i; sort(sa + 1, sa + n + 1, [](int x, int y) { return rk[x] == rk[y] ? rk[x + w] < rk[y + w] : rk[x] < rk[y]; }); // 这里用到了 lambda memcpy(oldrk, rk, sizeof(rk)); // 由于计算 rk 的时候原来的 rk 会被覆盖,要先复制一份 for (p = 0, i = 1; i <= n; ++i) { if (oldrk[sa[i]] == oldrk[sa[i - 1]] && oldrk[sa[i] + w] == oldrk[sa[i - 1] + w]) { rk[sa[i]] = p; } else { rk[sa[i]] = ++p; } // 若两个子串相同,它们对应的 rk 也需要相同,所以要去重 } } for (i = 1; i <= n; ++i) printf("%d ", sa[i]); return 0; }
#include <algorithm> #include <cstdio> #include <cstring> #include <iostream> using namespace std; const int N = 1000010; char s[N]; int n, sa[N], rk[N << 1], oldrk[N << 1], id[N], cnt[N]; int main() { int i, m, p, w; scanf("%s", s + 1); n = strlen(s + 1); m = max(n, 300); for (i = 1; i <= n; ++i) ++cnt[rk[i] = s[i]]; for (i = 1; i <= m; ++i) cnt[i] += cnt[i - 1]; for (i = n; i >= 1; --i) sa[cnt[rk[i]]--] = i; for (w = 1; w < n; w <<= 1) { memset(cnt, 0, sizeof(cnt)); for (i = 1; i <= n; ++i) id[i] = sa[i]; for (i = 1; i <= n; ++i) ++cnt[rk[id[i] + w]]; for (i = 1; i <= m; ++i) cnt[i] += cnt[i - 1]; for (i = n; i >= 1; --i) sa[cnt[rk[id[i] + w]]--] = id[i]; memset(cnt, 0, sizeof(cnt)); for (i = 1; i <= n; ++i) id[i] = sa[i]; for (i = 1; i <= n; ++i) ++cnt[rk[id[i]]]; for (i = 1; i <= m; ++i) cnt[i] += cnt[i - 1]; for (i = n; i >= 1; --i) sa[cnt[rk[id[i]]]--] = id[i]; memcpy(oldrk, rk, sizeof(rk)); for (p = 0, i = 1; i <= n; ++i) { if (oldrk[sa[i]] == oldrk[sa[i - 1]] && oldrk[sa[i] + w] == oldrk[sa[i - 1] + w]) { rk[sa[i]] = p; } else { rk[sa[i]] = ++p; } } } for (i = 1; i <= n; ++i) printf("%d ", sa[i]); return 0; }
for (i = 1, k = 0; i <= n; ++i) { if (k) --k; while (s[i + k] == s[sa[rk[i] - 1] + k]) ++k; ht[rk[i]] = k; // height太长了缩写为ht }
模板写法及变式(待更新)
询问子串[L,R]的出现次数
处理出height数组后左右二分找到第一个lcp小于R-L+1的坐标相减
求最长重复子串
max(height)即可
poj 1743
求不可重叠最长重复子串
二分答案(重复子串的长度)然后沿着sa做一遍分块,保证每个块中最多没有一个串的height小于所选答案,处理出此块中最大最小的下标,与枚举的答案长度做比较。
poj 3261
求可重叠出现k次的最长重复子串
二分答案(重复子串的长度)然后沿着sa做一遍分块,保证每个块中最多没有一个串的height小于所选答案,处理出此块中的串数是否大于k
spoj 694(重要)
求真实子串个数
len*(len-1)/2-sigma(height[i])
最长回文子串(重要)
S+'$'+反S跑一遍SA,然后分奇偶讨论情况
lcp(suf【i】,suf【n-i+1】) lcp(suf【i】,suf【n】)
poj 2406
求连续重复子串
枚举子串长度l,检验lcp(suf(0),suf(len))=n-len
poj3693
求重复次数最多的重复子串
枚举子串长度l,检验lcp(suf(0),suf(len))=n-len,求max(n/(len))
poj 2774
求最长公共子串
A+‘$’+B跑一遍sa,沿着sa求一遍不可重叠最长重复子串就ok
poj 3415
长度不小于k的公共子串个数
A+‘$’+B跑一遍sa+沿着sa搞单调栈再求不可重叠最长重复子串
未写题:
SPOJ DISUBSTR
SPOJ SUBST1
SPOJ REPEATs
POJ 3294
SPOJ PHRASEs
POJ 1226
UVA 11475
POJ 3581
POJ 3450
POJ 2758