一、KMP算法
int nex[n_max];
void getnext(char* p)
{
int len=strlen(p),k=-1,j=0;
nex[0]=-1;
while(j<len-1)
{
if(k==-1||p[j]==p[k]) nex[++j]=++k;
else k=nex[k];
}
}
int kmp(char* s,char* p)
{
int i=0,j=0,slen=strlen[s],plen=strlen(p);
while(i<slen&&j<plen)
{
if(j==-1||s[i]==p[j]) ++i,++j;
else j=nex[j];
}
if(j==plen) return i-j;
return -1;
}
二、Manacher算法
三、Trie树(字典树/前缀树)
四、AC自动机
#include <bits/stdc++.h>
#define For(i,x,y) for(int i=(x);i<=(y);++i)
#define Fov(i,x,y) for(int i=(x);i>=(y);--i)
#define Fo(i,x,y) for(int i=(x);i<(y);++i)
#define midf(a,b) ((a)+(b)>>1)
#define L p<<1
#define R (p<<1)|1
#define ss(_) scanf("%s",_)
#define si(_) scanf("%d",&_)
#define sii(x,y) scanf("%d%d",&x,&y)
#define siii(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define mem(x,y) memset(x,y,sizeof(x))
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
inline int read()
{
char ch=getchar(); int x=0, f=1;
while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar();}
while('0'<=ch&&ch<='9') { x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
const int inf=0x3f3f3f3f;
const double pi=acos(-1.0);
const int n_max=1e6+10;
char s[n_max];
int cnt,root;
struct node
{
int nex[26],fail,sum;
}tree[n_max*5];
int newnode()
{
Fo(i,0,26) tree[cnt].nex[i]=0;
tree[cnt].sum=0;
return cnt++;
}
void trie(char* s)
{
int len=strlen(s),cur=0;
Fo(i,0,len)
{
int x=s[i]-'a';
if(tree[cur].nex[x]==0) tree[cur].nex[x]=newnode();
cur=tree[cur].nex[x];
}
tree[cur].sum++;
}
void build()
{
queue<int>q;
Fo(i,0,26)
if(tree[root].nex[i]!=0)
{
tree[tree[root].nex[i]].fail=root;
q.push(tree[root].nex[i]);
}
while(!q.empty())
{
int cur=q.front();q.pop();
Fo(i,0,26)
{
if(tree[cur].nex[i]!=0)
{
tree[tree[cur].nex[i]].fail=tree[tree[cur].fail].nex[i];
q.push(tree[cur].nex[i]);
}
else tree[cur].nex[i]=tree[tree[cur].fail].nex[i];
}
}
}
int query(char* s)
{
int len=strlen(s),cur=0,ans=0;
Fo(i,0,len)
{
int x=s[i]-'a';
while(cur&&tree[cur].nex[x]==0) cur=tree[cur].fail;
cur=tree[cur].nex[x];
int p=cur;
while(p&&tree[p].sum>0)
{
ans+=tree[p].sum;
tree[p].sum=0;
p=tree[p].fail;
}
}
return ans;
}
int main()
{
int T;
si(T);
while(T--)
{
int n;
si(n);
cnt=0;
root=newnode();
For(i,1,n)
{
ss(s);
trie(s);
}
build();
ss(s);
printf("%d\n",query(s));
}
return 0;
}
五、回文自动机
题目:ACM-ICPC 2018 南京赛区网络预赛I---Skr
#include <bits/stdc++.h>
#define For(i,x,y) for(int i=(x);i<=(y);++i)
#define Fov(i,x,y) for(int i=(x);i>=(y);--i)
#define Fo(i,x,y) for(int i=(x);i<(y);++i)
#define midf(a,b) ((a)+(b)>>1)
#define Num1(_) (_)<<1
#define Num2(_) ((_)<<1)|1
#define ss(_) scanf("%s",_)
#define si(_) scanf("%d",&_)
#define sii(x,y) scanf("%d%d",&x,&y)
#define siii(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define mem(x,y) memeset(x,y,sizeof(x))
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
inline int read()
{
char ch=getchar(); int x=0, f=1;
while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar();}
while('0'<=ch&&ch<='9') { x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
const int inf=0x3f3f3f3f;
const ll mod=1e9+7;
const double pi=acos(-1.0);
const int n_max=2e6+10;
char s[n_max];
int cnt,len[n_max],fail[n_max],c[n_max][10];
ll num[n_max],p[n_max];
int add(int x)
{
len[cnt]=x;
return cnt++;
}
int getfail(int x,int i)
{
while(s[i-len[x]-1]!=s[i]) x=fail[x];
return x;
}
int main()
{
ss(s+1);
s[0]='$';
int l=strlen(s+1);
p[0]=1;
For(i,1,l)
{
p[i]=p[i-1]*10%mod;
num[i]=(s[i]-'0'+num[i-1]*10)%mod;
}
add(0),add(-1);
fail[0]=1;
int last=0,now;
ll ans=0;
For(i,1,l)
{
int cur=getfail(last,i), x=s[i]-'0';
if(c[cur][x]==0)
{
now=add(len[cur]+2);
ans=(ans+num[i]+mod-num[i-len[now]]*p[len[now]]%mod)%mod;
fail[now]=c[getfail(fail[cur],i)][x];
c[cur][x]=now;
}
last=c[cur][x];
}
printf("%lld\n",ans);
return 0;
}
六、后缀自动机(SAM)
①子串出现频率
题目:ACM-ICPC 2018 焦作赛区网络预赛H---String and Times
len[i]:状态i的最长子串长度
order[i]:按len升序排序后排在第i位的状态
endpos[i]:状态i中子串结束位置个数,也就是子串出现频率
建立后缀自动机,主链上每个状态的endpos初始化为1;执行reorder()后得到每个状态的顺序,按从大到小的顺序也就是len从大到小扫描每个状态,更新侧链状态的出现频率,对于满足条件的状态i,含有的子串个数很明显为len[i]-len[link[i]];例如,i的最长子串为abcd,link[i]的最长子串为cd,则i中含有的子串为abcd和bcd。
#include <bits/stdc++.h>
#define For(i,x,y) for(int i=(x);i<=(y);++i)
#define Fov(i,x,y) for(int i=(x);i>=(y);--i)
#define Fo(i,x,y) for(int i=(x);i<(y);++i)
#define midf(a,b) ((a)+(b)>>1)
#define L(_) (_)<<1
#define R(_) ((_)<<1)|1
#define fi first
#define se second
#define ss(_) scanf("%s",_)
#define si(_) scanf("%d",&_)
#define sii(x,y) scanf("%d%d",&x,&y)
#define siii(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define sl(_) scanf("%lld",&_)
#define mem(x,y) memset(x,y,sizeof(x))
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
inline int read()
{
char ch=getchar(); int x=0, f=1;
while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar();}
while('0'<=ch&&ch<='9') { x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
const int inf=0x3f3f3f3f;
const double pi=acos(-1.0);
const int n_max=2e5+10;
int ch[n_max*2][26],len[n_max*2],order[n_max*2],endpos[n_max*2],link[n_max*2],sum[n_max];
int cnt,last;
char s[n_max];
void init()
{
mem(ch,0);
mem(sum,0);
mem(endpos,0);
cnt=last=1;
link[1]=0;
len[1]=0;
}
void extend(int x)
{
int p=last,cur=last=++cnt;
len[cur]=len[p]+1,endpos[cur]=1;
while(p&&!ch[p][x]) ch[p][x]=cur,p=link[p];
if(p==0) link[cur]=1;
else
{
int q=ch[p][x];
if(len[q]==len[p]+1) link[cur]=q;
else
{
int clone=++cnt;
memcpy(ch[clone],ch[q],sizeof(ch[q]));
len[clone]=len[p]+1,link[clone]=link[q],link[q]=link[cur]=clone;
while(p&&ch[p][x]==q) ch[p][x]=clone,p=link[p];
}
}
}
void resort()
{
For(i,1,cnt) ++sum[len[i]];
For(i,1,len[last]) sum[i]+=sum[i-1];
For(i,1,cnt) order[sum[len[i]]--]=i;
}
int main()
{
//freopen("in.txt","r",stdin);
int a,b;
while(~ss(s))
{
sii(a,b);
init();
int l=strlen(s);
Fo(i,0,l) extend(s[i]-'A');
resort();
ll ans=0;
Fov(i,cnt,1)
{
int p=order[i],np=link[p];
endpos[np]+=endpos[p];
if(endpos[p]>=a&&endpos[p]<=b) ans+=len[p]-len[np];
}
printf("%lld\n",ans);
}
return 0;
}