Loading

字符串算法模板

字符串算法都好抽象啊……

1. 字符串哈希

int hash(string s)
{
    int ans=0,l=s.length();
    for(int i=0;i<l;i++)ans=(ans*base%mod+(s[i]-'0'+1))%mod;
    return ans;
}

2. 前缀函数

void prefix()
{
    for(int i=1;i<=n-1;i++)
    {
        int j=pi[i-1];
        while(j>0&&s[i]!=s[j])j=pi[j-1];
        if(s[i]==s[j])j++;
        pi[i]=j;
    }
}

3. manacher

l=s.length();t+="~#";
for(int i=0;i<l;i++){t+=s[i];t+='#';}
l=2*l+2;
for(int i=1;i<l;i++)
{
    if(maxr>i)r[i]=min(maxr-i,r[2*o-i]);
    for(;t[i+r[i]+1]==t[i-r[i]-1];r[i]++);
    if(i+r[i]>maxr){maxr=i+r[i];o=i;}
    ans=max(ans,r[i]);
}

4. Trie树

void insert(string s)
{
    int u=0,l=s.length();
    for(int i=0;i<l;i++)
    {
        int now=s[i]-'a';
        if(!trie[u][now])trie[u][now]=++tot;
        u=trie[u][now];
    }
    cnt[u]++;
}
int query(string s)
{
    int u=0,l=s.length();
    for(int i=0;i<l;i++)
    {
        if(flag[u]==1)return 0;
        int now=s[i]-'a';
        if(!trie[u][now])return 0;
        u=trie[u][now];
    }
    return cnt[u];
}

5. 最小表示法

int i=0,j=1,k=0;
while(i<n&&j<n&&k<n)
{
    if(s[(i+k)%n]==s[(j+k)%n]){k++;continue;}
    if(s[(i+k)%n]<s[(j+k)%n])j=j+k+1;
    else i=i+k+1;
    if(i==j)j++;
    k=0;
}
ans=min(i,j);

6. Z函数

for(int i=1;i<n;i++)
{
    if(r>i)z[i]=min(z[i-l],r-i+1);
    for(;b[i+z[i]]==b[z[i]];z[i]++);
    if(i+z[i]-1>r){l=i;r=i+z[i]-1;}
}

7. 失配树(Border树)

const int maxn=1000010;
string s;
int n,m,pi[maxn];
int cnt,h[maxn],anc[maxn][30],dep[maxn],lg2[maxn];
struct edge{int to,nxt;}e[maxn];
void addedge(int u,int v)
{
    e[++cnt]=(edge){v,h[u]};
    h[u]=cnt;
}
void prefix()
{
    for(int i=1;i<=n-1;i++)
    {
        int j=pi[i-1];
        while(j>0&&s[i]!=s[j])j=pi[j-1];
        if(s[i]==s[j])j++;
        pi[i]=j;
    }
}
void dfs(int u,int fa)
{
    anc[u][0]=fa;dep[u]=dep[fa]+1;
    for(int i=1;i<=lg2[dep[u]];i++)anc[u][i]=anc[anc[u][i-1]][i-1];
    for(int i=h[u];i;i=e[i].nxt)
    {
        int p=e[i].to;
        if(p!=fa)dfs(p,u);
    }
}
int lca(int u,int v)
{
    if(dep[u]>dep[v])swap(u,v);
    while(dep[u]<dep[v])v=anc[v][lg2[dep[v]-dep[u]]];
    if(u==v)return u;
    for(int k=lg2[dep[u]];k>=0;k--)
        if(anc[u][k]!=anc[v][k])
        {
            u=anc[u][k];
            v=anc[v][k];
        }
    return anc[u][0];
}
//main函数内
cin >> s >> m;n=s.length();prefix();
for(int i=1;i<=n;i++)addedge(pi[i-1],i);
for(int i=2;i<=n;i++)lg2[i]=lg2[i/2]+1;
dep[0]=-1;dfs(0,0);
for(int i=1;i<=m;i++)
{
    int p,q,f;cin >> p >> q;f=lca(p,q);
    if(f==p||f==q)cout << anc[f][0] << endl;
    else cout << f << endl;
}

8. 子序列自动机

const int maxn=100010;
int type,n,q,m,cnt,rt[maxn],a[maxn],s[maxn];
struct node{int l,r,val;}tree[maxn*20];
void build(int &x,int l,int r)
{
    x=++cnt;
    if(l==r){tree[x].val=a[l];return;}
    int mid=(l+r)>>1;
    build(tree[x].l,l,mid);
    build(tree[x].r,mid+1,r);
}
void modify(int &k,int ver,int x,int l,int r,int val)
{
    k=++cnt;tree[k]=tree[ver];
    if(l==r){tree[k].val=val;return;}
    int mid=(l+r)>>1;
    if(x<=mid)modify(tree[k].l,tree[ver].l,x,l,mid,val);
    else modify(tree[k].r,tree[ver].r,x,mid+1,r,val);
}
int query(int k,int x,int l,int r)
{
    if(l==r)return tree[k].val;
    int mid=(l+r)>>1;
    if(x<=mid)return query(tree[k].l,x,l,mid);
    else return query(tree[k].r,x,mid+1,r);
}
//main函数内
for(int i=0;i<n;i++)s[i]=read();
memset(a,-1,sizeof(a));
build(rt[n],1,m);
for(int i=n-1;i>=0;i--)modify(rt[i],rt[i+1],s[i],1,m,i+1);
for(int i=1;i<=q;i++)
{
    int l=read(),c,p,now=0,flag=1;
    for(int j=0;j<l;j++)
    {
        c=read();
        if(!flag)continue;
        p=query(rt[now],c,1,m);
        if(p==-1){flag=0;continue;}
        now=p;
    }
    if(!flag)printf("No\n");
    else printf("Yes\n");
}

9. AC自动机(ACAM)

const int maxn=200010;
int n,tot,trie[maxn][26],fail[maxn],point[maxn];
string s[maxn],t;
queue<int> q;
int cnt,h[maxn],siz[maxn];
struct edge{int to,nxt;}e[maxn];
void addedge(int u,int v)
{
    e[++cnt]=(edge){v,h[u]};
    h[u]=cnt;
}
void buildtrie()
{
    for(int i=1;i<=n;i++)
    {
        int u=0,l=s[i].length();
        for(int j=0;j<l;j++)
        {
            int now=s[i][j]-'a';
            if(!trie[u][now])trie[u][now]=++tot;
            u=trie[u][now];
        }
        point[i]=u;
    }
}
void buildac()
{
    for(int i=0;i<26;i++)if(trie[0][i])q.push(trie[0][i]);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=0;i<26;i++)
            if(trie[u][i])
            {
                fail[trie[u][i]]=trie[fail[u]][i];
                q.push(trie[u][i]);
            }
            else trie[u][i]=trie[fail[u]][i];
    }
}
void match(string ss)
{
    int u=0,l=ss.length();
    for(int i=0;i<l;i++)
    {
        u=trie[u][ss[i]-'a'];
        siz[u]++;
    }
}
void dfs(int u)
{
    for(int i=h[u];i;i=e[i].nxt)
    {
        int p=e[i].to;
        dfs(p);
        siz[u]+=siz[p];
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin >> n;
    for(int i=1;i<=n;i++)cin >> s[i];
    buildtrie();
    buildac();
    cin >> t;match(t);
    for(int i=1;i<=tot;i++)addedge(fail[i],i);
    dfs(0);
    for(int i=1;i<=n;i++)cout << siz[point[i]] << endl;
    return 0;
}

10. 回文自动机(PAM)

11. 后缀数组(SA)

12. 后缀自动机(SAM)

13. 广义后缀自动机(广义SAM)

14. Lyndon分解

posted @ 2021-07-11 22:48  pjykk  阅读(71)  评论(0编辑  收藏  举报