kmp
牛客多校带回退的kmp
#include <bits/stdc++.h>
using namespace std;
int n;
int len[5];
int ans[100005];
char ch[5][100005];
char pro[100005];
int f[100005];
int f2[100005];
int lenp;
int q[100005];
void getfail(char *p,int len){
f[0]=f[1]=f2[0]=f2[1]=0;
for(int i=1;i<len;i++){
int j=f2[i];
while(j&&p[i]!=p[j])j=f2[j];
f2[i+1] = f[i+1] = (p[i]==p[j])?j+1:0;
if(f[i+1]==j+1 && p[i+1]==p[j+1])f[i+1]=f[j+1];
}
/**
带退格的优化kmp:
当在p[i+1]的位置失配的时候,如果普通kmp的p[i+1]指向p[j+1]
并且他们相同,那么下次匹配依旧还是失配的,就会继续跳到p[f[j+1]]
如此下来失配的时候刚好会跳到本该在的位置
**/
}
void kmp(char *t,char *s,int id){
getfail(s,len[id]);
int j=0;
q[0]=0;
int r=0;
for(int i=0;i<lenp;i++){
if(t[i]=='-'){
if(r)r--;
j=q[r];
}
else{
while(j&&s[j]!=t[i])j=f[j];
if(s[j]==t[i])j++;
q[++r]=j;
}
ans[i] = min(ans[i] , len[id] - q[r]);
}
}
int main(){
scanf("%d",&n);
int temp=0x3f3f3f3f;
for(int i=0;i<n;i++){
scanf("%s",ch[i]);
len[i]=strlen(ch[i]);
temp=min(temp,len[i]);
}
printf("%d\n",temp);
memset(ans,0x3f,sizeof ans);
scanf("%s",pro);
lenp=strlen(pro);
for(int i=0;i<n;i++){
kmp(pro,ch[i],i);
}
for(int i=0;i<lenp;i++){
printf("%d\n",ans[i]);
}
return 0;
}
hash
typedef long long ll;
const int maxn = 2e5+10;
char s[maxn];
const int base = 233;
const int mod = 1e9+21;
int po[maxn],hs[maxn];
inline int md(ll x){
return x>=mod?x%mod:x;
}
inline int geth(int l,int r){
int ret = hs[r]-md((ll)hs[l-1]*po[r-l+1]);
return ret<0?ret+mod:ret;
}
int main(){
scanf("%s",s+1);len=strlen(s+1);
po[0]=1;
for(int i=1;i<=len;++i){
hs[i]=md((ll)hs[i-1]*base + s[i]);
po[i]=md((ll)po[i-1]*base);
}
return 0;
}
manacher
南京现场赛manacher + exkmp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e6+10;
char Ma[maxn<<1];
int Mp[maxn<<1];
void manacher(char s[],int len){
int l=0;
Ma[l++]='$';
Ma[l++]='#';
for(int i=0;i<len;i++){
Ma[l++]=s[i];
Ma[l++]='#';
}
Ma[l]=0;
int mx=0,id=0;
for(int i=0;i<l;i++){
Mp[i]=mx>i?min(Mp[2*id-i],mx-i):1;
while(Ma[i+Mp[i]]==Ma[i-Mp[i]])Mp[i]++;
if(i+Mp[i]>mx){
mx=i+Mp[i];
id=i;
}
}
}
void pre_EKMP(char x[],int m,int next[])
{
next[0]=m;
int j=0;
while(j+1<m && x[j]==x[j+1])j++;
next[1]=j;
int k=1;
for(int i=2; i<m; i++)
{
int p=next[k]+k-1;
int L=next[i-k];
if(i+L<p+1)next[i]=L;
else
{
j=max(0,p-i+1);
while(i+j<m && x[i+j]==x[j])j++;
next[i]=j;
k=i;
}
}
}
void EKMP(char x[],int m,char y[],int n,int next[],int extend[])
{
pre_EKMP(x,m,next);
int j=0;
while(j<n && j<m && x[j]==y[j])j++;
extend[0]=j;
int k=0;
for(int i=1; i<n; i++)
{
int p=extend[k]+k-1;
int L=next[i-k];
if(i+L<p+1)extend[i]=L;
else
{
j=max(0,p-i+1);
while(i+j<n && j<m && y[i+j]==x[j])j++;
extend[i]=j;
k=i;
}
}
}
char s[maxn],t[maxn];
int pre[maxn];
int extend[maxn],nxt[maxn];
int main(){
scanf("%s",s);
int lens=strlen(s);
manacher(s,lens);
for(int i=2;i<2*lens+2;i++){
if(Mp[i]<2)continue;
int idx = i/2;
int id = idx - Mp[i]/2+1;
pre[id]++;
pre[idx+1]--;
}
for(int i=1;i<=lens;i++){
pre[i]+=pre[i-1];
}
scanf("%s",t);
int lent=strlen(t);
reverse(s,s+lens);
EKMP(t,lent,s,lens,nxt,extend);
ll ans=0;
int j=lens-1;
for(int i=2;i<=lens;i++){
ans+=1ll*pre[i]*extend[j];
j--;
}
cout<<ans<<endl;
return 0;
}
回文自动机
hdu多校第二场的回文串题 pam + hash
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N = 26;
const int maxn = 3e5+10;
const int base=31;
ull hs[maxn],ht[maxn],po[maxn];
ull geth(int l,int r){return hs[r]-po[r-l+1]*hs[l-1];}
ull gett(int l,int r){return ht[l]-po[r-l+1]*ht[r+1];}
struct pam{
int nxt[maxn][N],fail[maxn];//在当前状态首尾添加字符的状态,失配跳到的状态
int len[maxn],S[maxn],ppos[maxn];//状态i表示的回文长度,缓存池,状态对应首次出现的位置
int cnt[maxn],num[maxn];//状态出现次数,以状态末尾结尾但不包含本条路径的数目
int last,n,p;//上个状态,总长度,当前状态编号
int newnode(int l){
memset(nxt[p],0,sizeof nxt[p]);
cnt[p]=num[p]=0;
len[p]=l;
return p++;
}
void init(){
p=0;
newnode(0);newnode(-1);
last=n=0;
S[n]=-1;
fail[0]=1;
}
int get_fail(int x){
while(S[n-len[x]-1]!=S[n])x=fail[x];return x;
}
void add(int c,int pos){
c-='a';
S[++n]=c;
int cur=get_fail(last);
if(!nxt[cur][c]){
int now=newnode(len[cur]+2);
ppos[now]=pos;
fail[now]=nxt[get_fail(fail[cur])][c];
nxt[cur][c]=now;
num[now]=num[fail[now]]+1;
}last=nxt[cur][c];cnt[last]++;
}
void Count(){
for(int i=p-1;i>=0;--i)cnt[fail[i]]+=cnt[i];
}
}p;
char s[maxn];
ull ans[maxn];
int main(){
po[0]=1;for(int i=1;i<maxn;++i)po[i]=po[i-1]*base;
while(scanf("%s",s+1)!=EOF){
p.init();
int len=strlen(s+1);
for(int i=1;i<=len;++i){
p.add(s[i],i);ans[i]=0;hs[i]=hs[i-1]*base+s[i];
}ht[len]=s[len];
for(int i=len-1;i;--i)ht[i]=ht[i+1]*base+s[i];
p.Count();
for(int i=2;i<p.p;++i){
int mid = (2*p.ppos[i]-p.len[i]+1)/2;
int mmid= (p.ppos[i]-p.len[i]+1+mid)/2;
if(geth(p.ppos[i]-p.len[i]+1,mmid) ==
gett(mmid+( (mid - p.ppos[i]-p.len[i] ) %2==0),mid) ){
ans[p.len[i]]+=p.cnt[i];
}
}
for(int i=1;i<=len;++i){
printf("%llu%c",ans[i]," \n"[i==len]);
}
}
return 0;
}
补充
if(len[now]<=2)half[now]=fail[now];
else{
int tmp=half[cur];
while( S[n-len[tmp]-1]!=S[n] || (len[tmp]+2)*2 > len[now] )tmp=fail[tmp];
half[now]=nxt[tmp][c];
}
int diff[maxn],snext[maxn];
/**
diff[x]表示x的最长回文后缀长度减少了多少
snext[x]表示fail链上第一个diff[y]!=diff[x]的状态
series[x]表示x -> snext[x]的链
*/
int f[maxn],series[maxn];
f[0]=1;
for(int i=1;i<=n;++i){
p.add(s[i],i);
for(int v=p.last;p.len[v]>0;v=p.snext[v]){
series[v]=f[i-(p.len[p.snext[v]]+p.diff[v])];
if(p.diff[v]==p.diff[p.fail[v]])
(series[v]+=series[p.fail[v]])%=mod;
(f[i]+=series[v])%=mod;
}if(i&1)f[i]=0;
}
cout<<f[n];
1 - 31 长度的回文串是否存在
f[0]=1;
for(int i=1; i<=n; i++) {
pam.insert(s[i]-'a');
for(int v=pam.last; pam.len[v]>0; v=pam.snext[v]) {
series[v]=f[i-(pam.len[pam.snext[v]]+pam.diff[v])];
if(pam.diff[v]==pam.diff[pam.next[v]])
series[v]|=series[pam.next[v]];
f[i]|=series[v]<<1;
}
printf("%u\n",f[i]>>1);
}
后缀数组
sais
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
cs int N=4e5;
namespace SA{
char s[N];
int sa[N],rk[N],ht[N],len;
int b[N],wb[N];
bool t[N<<1];
inline bool islms(int i,bool *cs t);
template<class T>
inline void induced_sort(T s,int len,int siz,int sigma,bool *cs t,int *cs cb,int *cs p);
template<class T>
inline void sais(T s,int len,bool *cs t,int *cs b1,int sigma);
inline void init(char str[],int len);
}
inline bool SA::islms(int i,bool *cs t){
return i>0&&t[i]&&!t[i-1];
}
template<class T>
inline void SA::induced_sort(T s,int len,int siz,int sigma,bool *cs t,int *cs cb,int *cs p){
memset(b,0,sigma<<2);
memset(sa,-1,len<<2);
for(int re i=0;i<len;++i)++b[s[i]];
cb[0]=b[0];
for(int re i=1;i<sigma;++i)cb[i]=cb[i-1]+b[i];
for(int re i=siz-1;~i;--i)sa[--cb[s[p[i]]]]=p[i];
for(int re i=1;i<sigma;++i)cb[i]=cb[i-1]+b[i-1];
for(int re i=0;i<len;++i)if(sa[i]>0&&!t[sa[i]-1])sa[cb[s[sa[i]-1]]++]=sa[i]-1;
cb[0]=b[0];
for(int re i=1;i<sigma;++i)cb[i]=cb[i-1]+b[i];
for(int re i=len-1;~i;--i)if(sa[i]>0&&t[sa[i]-1])sa[--cb[s[sa[i]-1]]]=sa[i]-1;
}
template<class T>
inline void SA::sais(T s,int len,bool *cs t,int *cs b1,int sigma){
int *cb=b+sigma,siz=0,cnt=0,p=-1;
t[len-1]=1;
for(int re i=len-2;~i;--i)t[i]=s[i]==s[i+1]?t[i+1]:(s[i]<s[i+1]);
for(int re i=1;i<len;++i)if(islms(i,t))b1[siz++]=i;
induced_sort(s,len,siz,sigma,t,cb,b1);
for(int re i=siz=0;i<len;++i)if(islms(sa[i],t))sa[siz++]=sa[i];
memset(sa+siz,-1,(len-siz)<<2);
for(int re i=0;i<siz;++i){
re int x=sa[i];
for(int re j=0;j<len;++j){
if(p==-1||s[x+j]!=s[p+j]||t[x+j]!=t[p+j]){
++cnt;p=x;
break;
}
else if(j>0&&(islms(x+j,t)||islms(p+j,t)))break;
}
sa[siz+(x>>1)]=cnt-1;
}
for(int re i=len-1,j=len-1;i>=siz;--i)if(~sa[i])sa[j--]=sa[i];
int *s1=sa+len-siz,*b2=b1+siz;
if(cnt<siz)sais(s1,siz,t+len,b1+siz,cnt);
else for(int re i=0;i<siz;++i)sa[s1[i]]=i;
for(int re i=0;i<siz;++i)b2[i]=b1[sa[i]];
induced_sort(s,len,siz,sigma,t,cb,b2);
}
inline void SA::init(char str[],int len1){
memset(ht,0,sizeof ht);
memset(rk,0,sizeof rk);
memset(b,0,sizeof b);
memset(wb,0,sizeof wb);
memset(t,0,sizeof t);
sais(s+1,len1+1,t,wb,128);
rk[0]=0,sa[0]=len1+1;
for(int re i=1;i<=len1;++i)rk[++sa[i]]=i;
for(int re i=1,k=0,j=0;i<len1;ht[rk[i++]]=k)
for(k?--k:0,j=sa[rk[i]-1];s[i+k]==s[j+k];++k);
}
/***/
int RMQ[N],mm[N];
int best[18][N];
void initRMQ(int n){
mm[0]=-1;
for(int i=1;i<=n;++i)
mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
for(int i=1;i<=n;i++)best[0][i]=i;
for(int i=1;i<=mm[n];i++)
for(int j=1;j+(1<<i)-1<=n;j++){
int a=best[i-1][j];
int b=best[i-1][j+(1<<(i-1))];
if(RMQ[a]<RMQ[b])best[i][j]=a;
else best[i][j]=b;
}
}
int askRMQ(int a,int b){
int t=mm[b-a+1];
b-=(1<<t)-1;
a=best[t][a];b=best[t][b];
return RMQ[a]<RMQ[b]?a:b;
}
int lcp(int a,int b){
//a=SA::rk[a];b=SA::rk[b];
if(a>b)swap(a,b);
return SA::ht[askRMQ(a+1,b)];
}
/***/
下一位置不确定的SA做法
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5;
char s[maxn+50];
int sa[maxn+50],rk[maxn+50];
int t[maxn+50],t2[maxn+50],c[maxn+50];
int nx[maxn+5][19];
int len,k;
queue<int> q[maxn+5];
void getsa(int m)//m表示最大字符的编码
{
memset(t,-1,sizeof(t));
memset(t2,-1,sizeof(t2));
int *x=t,*y=t2;
for(int i=0;i<m;++i) c[i]=0;
for(int i=0;i<len;++i) c[x[i]=s[i]]++;
for(int i=1;i<m;++i) c[i]+=c[i-1];
for(int i=len-1;i>=0;--i) sa[--c[x[i]]]=i;
for(int j=0,k=1;k<=len;k<<=1,++j)
{
/*int p=0;
for(int i=len-k;i<len;++i) y[p++]=i;
for(int i=0;i<len;++i) if(sa[i]>=k) y[p++]=sa[i]-k;*/
int p=0;
for(int i=0;i<len;++i) q[nx[i][j]].push(i);
for(int i=0;i<len;++i)
while(!q[sa[i]].empty())
{
y[p++]=q[sa[i]].front();
q[sa[i]].pop();
}
for(int i=0;i<m;++i) c[i]=0;
for(int i=0;i<len;++i) c[x[y[i]]]++;
for(int i=0;i<m;++i) c[i]+=c[i-1];
for(int i=len-1;i>=0;--i) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1,x[sa[0]]=0;
for(int i=1;i<len;++i)
if(y[sa[i-1]]==y[sa[i]]&&y[nx[sa[i-1]][j]]==y[nx[sa[i]][j]]) x[sa[i]]=p-1;else x[sa[i]]=p++;
if(p>=len) break;
m=p;
}
}
int main()
{
int T;
scanf("%d",&T);
for(int cas=1;cas<=T;++cas)
{
printf("Case #%d: ",cas);
scanf("%d",&len);
scanf("%s",s);
for(int i=0;i<len;++i) nx[i][0]=(1LL*i*i+1)%len;
for(int j=1;j<=18;++j)
for(int i=0;i<len;++i) nx[i][j]=nx[nx[i][j-1]][j-1];
getsa('9'+1);
int pos=sa[len-1];
for(int i=1;i<=len;++i,pos=nx[pos][0]) printf("%c",s[pos]);
printf("\n");
}
// for(int i=0;i<n;++i) printf("%d ",sa[i]);printf("\n");
// for(int i=0;i<n;++i) printf("%d ",rk[i]);printf("\n");
// for(int i=0;i<n;++i) printf("%d ",height[i]);printf("\n");
return 0;
}
两串相同子串个数
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 4e5+10;
char s1[maxn],s2[maxn];
int len1,len2;
pair<int,ll> stk[maxn];
struct SA{
int rk[maxn],sa[maxn],height[maxn];
int t1[maxn],t2[maxn],c[maxn];
bool cmp(int *s,int a,int b,int l){
return s[a]==s[b]&&s[a+l]==s[b+l];
}
void Sa(char *s,int n,int m){
n++;
int i,j,p,*x=t1,*y=t2;
for(i=0;i<m;i++)c[i]=0;
for(i=0;i<n;i++)c[x[i]=s[i]]++;
for(i=1;i<m;i++)c[i]+=c[i-1];
for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
for(j=1;j<=n;j<<=1){
p=0;
for(i=n-j;i<n;i++)y[p++]=i;
for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
for(i=0;i<m;i++)c[i]=0;
for(i=0;i<n;i++)c[x[y[i]]]++;
for(i=1;i<m;i++)c[i]+=c[i-1];
for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1;x[sa[0]]=0;
for(i=1;i<n;i++)x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
if(p>=n)break;m=p;
}
int k=0;n--;
for(i=0;i<=n;i++)rk[sa[i]]=i;
for(i=0;i<n;i++){
if(k)k--;
j=sa[rk[i]-1];
while(s[i+k]==s[j+k])k++;
height[rk[i]]=k;
}
}
void solve(int n){
ll ret=0;
int sum[maxn];sum[0]=0;
for(int i=1;i<=n;i++)sum[i]=sum[i-1]+(sa[i]<len1);
int top=0;
stk[0]=make_pair(1,0);
for(int i=1;i<=n;i++){
while(top &&height[ stk[top].first ]>height[i])top--;++top;
stk[top]=make_pair(i,(sum[i-1]-sum[stk[top-1].first-1])*height[i]+stk[top-1].second);
if(sa[i]>len1)ret+=stk[top].second;
}top=0;
for(int i=1;i<=n;i++)sum[i]=sum[i-1]+(sa[i]>len1);
for(int i=1;i<=n;i++){
while(top &&height[ stk[top].first ]>height[i])top--;top++;
stk[top]=make_pair(i,(sum[i-1]-sum[stk[top-1].first-1])*height[i]+stk[top-1].second);
if(sa[i]<len1)ret+=stk[top].second;
}cout<<ret;
}
}sa;
char s[maxn];
int main(){
scanf("%s%s",s1,s2);
len1=strlen(s1);len2=strlen(s2);
int n=0;
for(int i=0;i<len1;i++)s[n++]=s1[i];
s[n++]='$';
for(int i=0;i<len2;i++)s[n++]=s2[i];
s[n]=0;
sa.Sa(s,n,128);
sa.solve(n);
return 0;
}
AC自动机
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
char t[151][80];
int cnt[151];
char s[maxn];
int n;
struct trie{
int nxt[maxn][26],fail[maxn];
int ed[maxn];
int rt,L;
int newnode(){
memset(nxt[L],-1,sizeof nxt[L]);
ed[L++]=0;
return L-1;
}
void init(){
L=0;rt=newnode();
}
void insert(int id,char buf[]){
int len=strlen(buf);
int now=rt;
for(int i=0;i<len;++i){
if(nxt[now][buf[i]-'a']==-1)nxt[now][buf[i]-'a']=newnode();
now=nxt[now][buf[i]-'a'];
}ed[now]=id;
}
void build(){
queue<int>q;
fail[rt]=rt;
for(int i=0;i<26;++i){
if(nxt[rt][i]==-1)nxt[rt][i]=rt;
else {
fail[nxt[rt][i]]=rt;
q.push(nxt[rt][i]);
}
}
while(!q.empty()){
int now = q.front();q.pop();
for(int i=0;i<26;++i){
if(nxt[now][i]==-1)nxt[now][i]=nxt[fail[now]][i];
else{
fail[nxt[now][i]]=nxt[fail[now]][i];
q.push(nxt[now][i]);
}
}
}
}
void query(char buf[]){
int len=strlen(buf);
int now = rt;
for(int i=0;i<len;++i){
now = nxt[now][buf[i]-'a'];
int tmp=now;
while(tmp!=rt){
cnt[ed[tmp]]++;
tmp=fail[tmp];
}
}
}
}ac;
int main(){
while(cin>>n&&n){
ac.init();
memset(cnt,0,sizeof cnt);
for(int i=1;i<=n;++i){
scanf("%s",t[i]);
ac.insert(i,t[i]);
}ac.build();
scanf("%s",s);
ac.query(s);
}
return 0;
}
SAM
最短不重复子串4合1
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 4e3+10;
char a[maxn],b[maxn];
int lena,lenb;
struct SEM{
int nxt[maxn][26];
int len;
inline void init(char *s,int l){
len=l;
for(int i=0;i<26;i++)nxt[len][i]=len;
for(int i=len-1;i>=0;i--){
memcpy(nxt[i],nxt[i+1],sizeof nxt[i+1]);
nxt[i][s[i]-'a']=i;
}
}
}AA,BB;
struct SAM{
int pa[maxn<<1],son[maxn<<1][27];
int deep[maxn<<1],cnt,root,last;
inline int newnode(int _deep){
deep[++cnt]=_deep;
return cnt;
}
inline void sam(int alp){
int np=newnode(deep[last]+1);
int u=last;
memset(son[np],0,sizeof son[np]);
while(u&&!son[u][alp])son[u][alp]=np,u=pa[u];
if(!u)pa[np]=root;
else{
int v=son[u][alp];
if(deep[v]==deep[u]+1)pa[np]=v;
else{
int nv=newnode(deep[u]+1);
memcpy(son[nv],son[v],sizeof son[v]);
pa[nv]=pa[v],pa[v]=pa[np]=nv;
while(u&&son[u][alp]==v)son[u][alp]=nv,u=pa[u];
}
}last=np;
}
inline void pre(){
cnt=0;
memset(son[1],0,sizeof son[1]);
root=last=newnode(0);
}
}A,B;
int solve1(){
int ret=inf;
for(int i=0;i<lena;i++){
int pos=B.root;
for(int j=i;j<lena;j++){
if(B.son[pos][a[j]-'a'])pos=B.son[pos][a[j]-'a'];
else{
ret=min(ret,j-i+1);break;
}
}
}return ret==inf?-1:ret;
}
int solve2(){
int ret=inf;
for(int i=0;i<lena;i++){
int pos=0;
for(int j=i;j<lena;j++){
if(BB.nxt[pos][a[j]-'a']==BB.len){
ret=min(ret,j-i+1);break;
} else pos=BB.nxt[pos][a[j]-'a']+1;
}
}return ret==inf?-1:ret;
}
int solve3(){
int ret=inf;
int dp[maxn];//dp[i]表示状态i能够接受的最短A的子序列
memset(dp,0x3f,sizeof dp);
dp[1]=0;
for(int i=0;i<lena;i++){
for(int j=B.root;j<=B.cnt;j++){
if(B.son[j][a[i]-'a']){
dp[B.son[j][a[i]-'a']]=min(dp[B.son[j][a[i]-'a']],dp[j]+1);
} else ret=min(ret,dp[j]+1);
}
}return ret==inf?-1:ret;
}
struct node{
int a,b,step;
node(int a=0,int b=0,int step=0):a(a),b(b),step(step){}
};
bool vis[maxn][maxn]={0};
int solve4(){
queue<node> q;
q.push(node(0,0,0));
while(!q.empty()){
node now=q.front();q.pop();
//cout<<now.a<<" "<<now.b<<" "<<now.step<<endl;
for(int i=0;i<26;i++){
if(AA.nxt[now.a][i]==AA.len)continue;
if(vis[AA.nxt[now.a][i]][BB.nxt[now.b][i]])continue;
if(BB.nxt[now.b][i]==BB.len)return now.step+1;
vis[AA.nxt[now.a][i]][BB.nxt[now.b][i]]=1;
q.push(node(AA.nxt[now.a][i]+1,BB.nxt[now.b][i]+1,now.step+1));
}
}return -1;
}
int main(){
scanf("%s%s",a,b);
lena=strlen(a);
lenb=strlen(b);
A.pre();B.pre();
for(int i=0;i<lena;i++)A.sam(a[i]-'a');
for(int i=0;i<lenb;i++)B.sam(b[i]-'a');
AA.init(a,lena);BB.init(b,lenb);
printf("%d\n",solve1());
printf("%d\n",solve2());
printf("%d\n",solve3());
printf("%d\n",solve4());
return 0;
}
允许3次失配的子串匹配
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
int tran(char c){
if(c=='A')return 0;if(c=='T')return 1;if(c=='C')return 2;if(c=='G')return 3;
}
char s1[maxn],s2[maxn];
int len1,len2;
struct SAM{
int pa[maxn<<1],son[maxn<<1][4];
int deep[maxn<<1],cnt,root,last;
int sum[maxn<<1],topo[maxn<<1];
int r[maxn<<1];
inline void pre(){
memset(r,0,sizeof r);
}
inline void toposort(){
int tmp=root;
for(int a=0;a<len1;a++){
tmp=son[tmp][tran(s1[a])];
r[tmp]=1;
}
memset(sum,0,sizeof sum);
for(int a=1;a<=cnt;a++)sum[deep[a]]++;
for(int a=1;a<=deep[last];a++)sum[a]+=sum[a-1];
for(int a=1;a<=cnt;a++)topo[sum[deep[a]]--]=a;
for(int a=cnt;a>=1;a--)r[pa[topo[a]]] += r[topo[a]];
}
}A;
int ans;
void dfs(int pos1,int pos2,int lim){
if(lim>3)return;
if(pos2==len2){
ans+=A.r[pos1];return;
}
for(int a=0;a<4;a++){
if(A.son[pos1][a]){
dfs(A.son[pos1][a],pos2+1,lim+(a!=tran(s2[pos2])));
}
}
}
int main(){
int t;cin>>t;
while(t--){
ans=0;
scanf("%s%s",s1,s2);
A.pre();
len1=strlen(s1);len2=strlen(s2);
for(int i=0;i<len1;i++)A.sam(tran(s1[i]));
A.toposort();
dfs(1,0,0);
printf("%d\n",ans);
}
return 0;
}
第k小子串
/**T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+1000;
char s[maxn];
int pa[maxn<<1],son[maxn<<1][27];
int deep[maxn<<1],cnt,root,last;
int sum[maxn<<1],topo[maxn<<1];
int r[maxn<<1],rr[maxn<<1];
inline void sam(int alp){
r[np]=1;
}
inline void toposort(){
for(int a=1;a<=cnt;a++)sum[deep[a]]++;
for(int a=1;a<=deep[last];a++)sum[a]+=sum[a-1];
for(int a=1;a<=cnt;a++)topo[sum[deep[a]]--]=a;
}
int T,K;
int main(){
scanf("%s%d%d",s,&T,&K);
pre();
memset(son[1],0,sizeof son[1]);
int len=strlen(s);
for(int a=0;a<len;a++){
sam(s[a]-'a');
}
toposort();
for(int i=cnt;i;i--){
if(T)r[pa[topo[i]]] += r[topo[i]];
else r[topo[i]]=1;
}
r[root]=0;
for(int i=cnt;i;i--){
rr[topo[i]]=r[topo[i]];
for(int j=0;j<26;j++){
rr[topo[i]]+=rr[son[topo[i]][j]];
}
}
int now=root;
if(K>rr[root])return puts("-1");
while(K){
K-=r[now];
if(K<=0)break;
for(int i=0;i<26;i++){
if(son[now][i]){
if(rr[son[now][i]]>=K){
putchar(i+'a');
now=son[now][i];
break;
}
else K-=rr[son[now][i]];
}
}
}
puts("");
return 0;
}
出现次数在[A,B]之间的子串个数
int tmp=root;
for(int a=0;a<len;a++){
tmp=son[tmp][s[a]-'A'];
r[tmp]=1;
}
/**将所有状态的right集合大小赋值为1**/
for(int a=cnt;a>=1;a--)r[pa[topo[a]]] += r[topo[a]];
long long ans=0;
for(int a=cnt;a>=1;a--){
if(r[topo[a]]>=A && r[topo[a]]<=B){
ans+=deep[topo[a]] - deep[pa[topo[a]]];
/**right集合中不同子串个数为deep[p] - deep[pa[p]]]**/
}
}
cout<<ans<<endl;
两串LCS
for(int a=0;a<len;a++)sam(s[a]-'a');
for(int a=1,l=0,p=1;a<=m;a++){
int x=t[a]-'a';
if(son[p][x])p=son[p][x],l++;
else{
for(;p&&!son[p][x];p=pa[p]);
if(!p)l=0,p=1;
else l=deep[p]+1,p=son[p][x];
}
/**
p表示当前在哪个状态,l表示当前状态匹配的最长子串
deep[p]表示在p状态下,得到的最长子串的长度
**/
ans=max(ans,l);
}
printf("%d\n",ans);
多个串的LCS
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
char s[maxn];
int pa[maxn<<1],son[maxn<<1][27];
int deep[maxn<<1],cnt,root,last;
int sum[maxn<<1],topo[maxn<<1];
int arr[maxn<<1],ned[maxn<<1];
inline int newnode(int _deep){
deep[++cnt]=_deep;
return cnt;
}
inline void sam(int alp){
}
inline void toposort(){
for(int a=1;a<=cnt;a++)sum[deep[a]]++;
for(int a=1;a<=deep[last];a++)sum[a]+=sum[a-1];
for(int a=1;a<=cnt;a++)topo[sum[deep[a]]--]=a;
}
inline void pre(){
root=last=newnode(0);
}
int main(){
scanf("%s",s);
pre();
memset(son[1],0,sizeof son[1]);
int len=strlen(s);
for(int a=0;a<len;a++)sam(s[a]-'a');
toposort();
for(int a=1;a<=cnt;a++)ned[a]=deep[a];
while(scanf("%s",s+1)!=EOF){
int m=strlen(s+1);
for(int a=1,l=0,p=1;a<=m;a++){
int x=s[a]-'a';
if(son[p][x])p=son[p][x],l++;
else{
for(;p && !son[p][x];p=pa[p]);
if(!p)l=0,p=1;
else l=deep[p]+1,p=son[p][x];
}
arr[p]=max(arr[p],l);
}
for(int a=cnt;a>=1;a--){
int p=topo[a];
ned[p]=min(ned[p],arr[p]);
if(arr[p]&&pa[p])arr[pa[p]]=deep[pa[p]];
arr[p]=0;
}
}
int ans=0;
for(int a=1;a<=cnt;a++)ans=max(ans,ned[a]);
printf("%d\n",ans);
return 0;
}
区间[L,R]内不同子串个数
inline void sam(int alp){
tot+=deep[np]-deep[pa[np]];
}
inline void pre(){
cnt=0;
memset(son[1],0,sizeof son[1]);
root=last=newnode(0);
tot=0;
}
for(int i=0;i<len;i++){
pre();
for(int j=i;j<len;j++){
sam(s[j]-'a');
ans[i][j]=tot;
}
}
int q;scanf("%d",&q);
while(q--){
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",ans[l-1][r-1]);
}
统计长度为[1..l]的子串最多出现次数
int tmp=root;
for(int a=0;a<len;a++){
tmp=son[tmp][s[a]-'a'];
r[tmp]=1;
}
/***将原串前缀状态的right集合大小设为1,
相当于在后缀树中将后缀结点标记为1**/
toposort();
/**deep[a] > deep[pa[a]],所以排序,
用a状态更新pa[a]的状态,只考虑结点的deep便可
**/
for(int a=cnt;a>=1;a--)r[pa[topo[a]]] += r[topo[a]];/**right表示状态在整个串出现次数**/
for(int a=1;a<=cnt;a++)f[deep[a]] = max(f[deep[a]] , r[a]);/**只更新最长串**/
for(int a=len;a>=1;a--)f[a-1]=max(f[a],f[a-1]);/**长串更新短串:短串包含在长串里面**/
for(int i=1;i<=len;i++)printf("%d\n",f[i]);
最小表示法
int minpre(char s[]){
int m = strlen(s);
memcpy(s + m, s,m*sizeof(char));
int i = 0,j = 1;//i表示从i往后是有可能的,j表示下一个试探的位置
while(j < m && i < m) {
int k;
for (k = 0;s[i + k] == s[j + k] && k < m; k++)
if(k == m ) return min(i,j);//如果相等了,那最小的就是答案
if(s[i + k] > s[j + k]) i = i + k + 1;//i到i+k开始的都不可能
else (j = j + k + 1);//同上
if (i == j) j++;//刚好相等,重新比较
}
if(i < m) return i;
else return j;
}
int main(){
char s[20005];
int n;
scanf("%d",&n);
while(n--){
scanf("%s",s);
printf("%d\n",minpre(s) + 1);
}
}