字符串

一、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自动机

题目:HDU2222---Keywords Search

#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;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值