zoukankan      html  css  js  c++  java
  • SPOJ LCS2 后缀自动机

    题目传送门

    题目大意:还是求字符串的最长公共子串,只不过这次是n个串。

    思路:

      先把第一个串丢到SAM里面去,然后每一个串都和前面那个串做一次最长公共子串的匹配。我们现在把SAM里面的其中一个状态记做$p$,这个$p$其实就代表了$right$集合相同的所有子串,我们要记录每一个状态下的最大匹配长度(通俗的理解,有一个子串是p,所有串的公共子串就是这个p)。然后把所有匹配串和原串都匹配一遍,每个$p$模式下取最小值。

      但是这里会有一个问题,假设我们此时有$aaaaaab$,$aaaaaab$,$cccaaab$这样三个串,按照如上方式匹配,会发现$aaab$这个答案串对应的p会被我们忽略掉(在拿第二个串和第一个串匹配的时候,直接一路到底了,$aaab$这个串的p根本就没有更新),我们遗漏了答案,原因是我们在更新$aaaaaab$的时候,并没有更新$aaab$。

      那要怎么办呢?我们会发现,$aaab$是$aaaaaab$的父串之一,所以,mxi可以更新mx[i.parent] ,为了使得更快的更新且不重复,我们先处理所有长度比较长的p,然后每个p都更新长度短一些的父串。这里用的是拓扑排序,看代码会更容易理解一些。要区别好拓扑排序的$i$是从1开始的还是从$tot$开始的。

      PS:强烈谴责网上几个代码根本AC不了的博客,有几个甚至第三组就wa了,我自动机模板写错的时候都过了九组数据。而且这样的博客还不止一个。。

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const int maxn=100010;
    char s[maxn];
    int len[maxn<<1],ch[maxn<<1][27],fa[maxn<<1],tot=1,root=1,last=1,siz;
    void extend(int x){
        int now=++tot,pre=last;
        last=now,len[now]=len[pre]+1;
        while( pre && !ch[pre][x]){
            ch[pre][x]=now;
            pre=fa[pre];
        }
        if(!pre)fa[now]=root;
        else{
            int q = ch[pre][x];
            if(len[q]==len[pre]+1)fa[now]=q;
            else {
                int nows=++tot;
                memcpy(ch[nows],ch[q],sizeof(ch[q]));
                len[nows]=len[pre]+1;
                fa[nows]=fa[q];
                fa[q]=fa[now]=nows;
                while(pre&&ch[pre][x]==q){
                    ch[pre][x]=nows;
                    pre=fa[pre];
                }
            }
        }
    }
    int mn[maxn<<1],mx[maxn<<1],c[maxn<<1],a[maxn<<1];
    int main(){
        scanf("%s",s);
        siz=strlen(s);
        for(int i=0;i<siz;i++)
        {
            int p=s[i]-'a';
            extend(p);
        }
        for(int i=1;i<=tot;i++)c[len[i]]++;
        for(int i=1;i<=tot;i++)c[i]+=c[i-1];
        for(int i=tot;i>0;i--)a[c[len[i]]--]=i;
        for(int i=tot;i>0;i--)mn[i]=len[i];
        while(scanf("%s",s)!=EOF){
            clr(mx,0);
            int cur=1,maxx=0;
            siz=strlen(s);
            for(int i=0;i<siz;i++)
            {
                int p=s[i]-'a';
                if(ch[cur][p]){
                    maxx++;
                    cur=ch[cur][p];
                }else{
                    while(cur&&ch[cur][p]==0)cur=fa[cur];
                    if(cur){
                        maxx=len[cur]+1;
                        cur=ch[cur][p];
                    }else{
                        cur=1;
                        maxx=0;
                    }
                }
                mx[cur]=max(mx[cur],maxx);
            }
            for(int i=tot;i>0;i--){
                int p=a[i];
                mx[fa[p]]=max(mx[fa[p]],mx[p]);
            }
            for(int i=tot;i>0;i--)mn[i]=min(mn[i],mx[i]);
        }
        int ans=0;
        for(int i=tot;i>0;i--){
            ans=max(ans,mn[i]);
        }
        cout<<ans<<endl;
    }
  • 相关阅读:
    java性能优化之HashMap,LinkedHashMap,TreeMap读取大量数据效率的比较
    jdk8 stream实现sql单表select a,b,sum(),avg(),max() from group by a,b order by a,b limit M offset N及其性能
    postgresql cstore_fdw性能测试
    Oracle JDBC prefetch: how to avoid running out of RAM
    mysql-创建用户报错ERROR 1396 (HY000): Operation CREATE USER failed for 'root'@'localhost'
    kafka外部访问设置
    mysql 排序长度限制之max_length_for_sort_data以及mysql两种排序算法
    mybatis三个执行器的差别
    Dubbo的集群容错与负载均衡策略及自定义(一致性哈希路由的缺点及自定义)
    mysql中包含长字段索引的优化
  • 原文地址:https://www.cnblogs.com/mountaink/p/10662797.html
Copyright © 2011-2022 走看看