[自学笔记]各种自动机

AC自动机

yyb巨佬的博客

贴一个模板题的代码:

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int M = 1000005;
int read()
{
	int x=0,flag=1;char c;
	while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
	while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return x*flag;
}
int n;char s[M];
struct Automaton
{
	int c[M][26],val[M],fail[M],cnt;
	void ins(char *s)
	{
		int len=strlen(s),now=0;
		for(int i=0;i<len;i++)
		{
			int v=s[i]-'a';
			if(!c[now][v]) c[now][v]=++cnt;
			now=c[now][v];
		}
		val[now]++;
	}
	void build()
	{
		queue<int> q;
		for(int i=0;i<26;i++) if(c[0][i]) q.push(c[0][i]);
		while(!q.empty())
		{
			int t=q.front();
			q.pop();
			for(int i=0;i<26;i++)
				if(c[t][i]) fail[c[t][i]]=c[fail[t]][i],q.push(c[t][i]);
				else c[t][i]=c[fail[t]][i];
		}
	}
	int query(char *s)
	{
		int len=strlen(s),now=0,ans=0;
		for(int i=0;i<len;i++)
		{
			now=c[now][s[i]-'a'];
			for(int k=now;k&&~val[k];k=fail[k])
				if(val[k]>=0)
					ans+=val[k],val[k]=-1; 
		}
		return ans;
	}
}AC;
int main()
{
	n=read();
	for(int i=1;i<=n;i++)
	{
		scanf("%s",s);
		AC.ins(s);
	}
	AC.build();
	scanf("%s",s);
	printf("%d\n",AC.query(s));
}

后缀数组

转载自某巨佬

贴一个模板题的代码:

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int M = 1000005;
int read()
{
	int x=0,flag=1;char c;
	while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
	while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return x*flag;
}
int n,m,x[M],y[M],c[M],sa[M],rk[M];
char s[M];
void get_sa()
{
    for(int i=1;i<=n;i++) ++c[x[i]=s[i]];
    for(int i=2;i<=m;i++) c[i]+=c[i-1];
    for(int i=n;i>=1;i--) sa[c[x[i]]--]=i;
    for(int k=1;k<=n;k<<=1)
    {
        int num=0;
        for(int i=n-k+1;i<=n;i++) y[++num]=i;
        for(int i=1;i<=n;i++) if(sa[i]>k) y[++num]=sa[i]-k;
        for(int i=1;i<=m;i++) c[i]=0;
        for(int i=1;i<=n;i++) ++c[x[i]];
        for(int i=2;i<=m;i++) c[i]+=c[i-1];
        for(int i=n;i>=1;i--) sa[c[x[y[i]]]--]=y[i],y[i]=0;
        swap(x,y);
        x[sa[1]]=1;num=1;
        for(int i=2;i<=n;i++)
            x[sa[i]]=(y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
        if(num==n) break;
        m=num;
    }
    for(int i=1;i<=n;i++) printf("%d ",sa[i]);
}
int main()
{
    scanf("%s",s+1);
    n=strlen(s+1);m=122;
    get_sa();
}

后缀自动机

转载自某巨佬

贴一道模板题的代码:

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int M = 2000005;
int read()
{
 int x=0,flag=1;char c;
 while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
 while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
 return x*flag;
}
int n,cnt=1,last=1,tot,val[M],f[M];
char s[M];long long ans;
struct node
{
    int len,fa,ch[26];
    node() {memset(ch,0,sizeof ch);len=fa=0;}
}a[M];
struct edge
{
    int v,next;
    edge(int V=0,int N=0) : v(V) , next(N) {}
}e[2*M];
void add(int c)
{
    int p=last,np=last=++cnt;val[cnt]=1;
    a[np].len=a[p].len+1;
    for(;p && !a[p].ch[c];p=a[p].fa) a[p].ch[c]=np;
    if(!p) a[np].fa=1;
    else
    {
        int q=a[p].ch[c];
        if(a[q].len==a[p].len+1) a[np].fa=q;
        else
        {
            int nq=++cnt;
            a[nq]=a[q];a[nq].len=a[p].len+1;
            a[q].fa=a[np].fa=nq;
            for(;p && a[p].ch[c]==q;p=a[p].fa) a[p].ch[c]=nq;
        }
    }
}
void link(int u,int v)
{
    e[++tot]=edge(v,f[u]),f[u]=tot;
    e[++tot]=edge(u,f[v]),f[v]=tot;
}
void dfs(int u,int fa)
{
    for(int i=f[u];i;i=e[i].next)
    {
        int v=e[i].v;
        if(v==fa) continue;
        dfs(v,u);
        val[u]+=val[v];
    }
    if(val[u]!=1) ans=max(ans,1ll*val[u]*a[u].len);
}
int main()
{
    scanf("%s",s);
    n=strlen(s);
    for(int i=0;i<n;i++) add(s[i]-'a');
    for(int i=2;i<=cnt;i++) link(i,a[i].fa);
    dfs(1,0);
    printf("%lld\n",ans);
}

回文自动机

跟AC自动机很像,转载某巨佬的博客

贴一道模板题的代码:

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int M = 2000005;
int read()
{
 int x=0,flag=1;char c;
 while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
 while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
 return x*flag;
}
struct node
{
    int fail,len,num,ch[26];
    node() {memset(ch,0,sizeof ch);fail=len=num=0;}
};
struct Pam
{
    node b[M];char c[M];
    int n,len,last,cnt,s[M];
    Pam()
    {
        b[0].fail=1;b[1].len=-1;
        cnt=1;last=0;
    }
    void read()
    {
        scanf("%s",c+1);
        len=strlen(c+1);
    }
    int get_fail(int x)
    {
        while(s[n-b[x].len-1]^s[n])
        {
            x=b[x].fail;
        }
        return x;
    }
    void ins()
    {
        int p=get_fail(last);
        if(!b[p].ch[s[n]])
        {
            b[++cnt].len=b[p].len+2;
            int tmp=get_fail(b[p].fail);
            b[cnt].fail=b[tmp].ch[s[n]];
            b[cnt].num=b[b[cnt].fail].num+1;
            b[p].ch[s[n]]=cnt;
        }
        last=b[p].ch[s[n]];
    }
    void solve()
    {
        int k=0;
        s[0]=26;
        for(n=1;n<=len;n++)
        {
            c[n]=(c[n]-97+k)%26+97;
            s[n]=c[n]-'a';
            ins();
            printf("%d ",b[last].num);
            k=b[last].num;
        }
    }
}P;
int main()
{
    P.read();
    P.solve();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值