zoukankan      html  css  js  c++  java
  • BZOJ 3796: Mushroom追妹纸 后缀自动机+拓扑排序+DP

    就是喜欢后缀自动机,yy了一个只用后缀自动机解决的方法.   

    对 3 个串建立广义后缀自动机,然后建立后缀树.  

    标记出每个点在0/1/2个串中是否作为子串出现,然后将后缀树中 2 串结尾的所有子树都设为危险节点.  

    然后对于 SAM 来一个拓扑序DP,我们开始的时候默认危险节点的最大值是 -inf,然后 2 结尾节点最大值为 len(2)-1.  

    然后这么转移一下就好了. 

    最开始错误的原因误以为只要一个节点会从一个危险节点转移,那么该节点就是危险节点.    

    这个是错误的,而是要满足转移过来的节点全是危险节点,这个点才是危险节点. 

    code: 

    #include <cstdio> 
    #include <string>
    #include <algorithm>  
    #include <queue>
    #include <cstring>  
    #define N 300006 
    #define inf 1000000000 
    using namespace std;   
    void setIO(string s) 
    {
        freopen((s+".in").c_str(),"r",stdin);  
        // freopen((s+".out").c_str(),"w",stdout); 
    }
    char S[N];  
    queue<int>que;  
    int edges,dfn,ans,dp[N];  
    int ch[N][26],mx[N],pre[N],last,tot,tag[N][3],hd[N],to[N],nex[N],st[N],ed[N],is[N],deg[N];   
    void add(int u,int v) 
    {
        nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; 
    }
    void extend(int c,int id) 
    { 
        if(ch[last][c]) 
        {
            int p=last,q=ch[last][c];   
            if(mx[q]==mx[p]+1)  last=q;   
            else 
            {
                int nq=++tot;   
                mx[nq]=mx[p]+1;   
                memcpy(ch[nq],ch[q],sizeof(ch[nq]));   
                pre[nq]=pre[q],pre[q]=nq;   
                for(;p&&ch[p][c]==q;p=pre[p]) ch[p][c]=nq;   
                last=nq; 
            }
        }  
        else 
        {
            int np=++tot,p=last; 
            mx[np]=mx[p]+1,last=np; 
            for(;p&&!ch[p][c];p=pre[p]) ch[p][c]=np;  
            if(!p) pre[np]=1; 
            else 
            {
                int q=ch[p][c]; 
                if(mx[q]==mx[p]+1)  pre[np]=q;  
                else 
                {
                    int nq=++tot; 
                    mx[nq]=mx[p]+1;   
                    memcpy(ch[nq],ch[q],sizeof(ch[q]));    
                    pre[nq]=pre[q],pre[q]=pre[np]=nq;     
                    for(;p&&ch[p][c]==q;p=pre[p])  ch[p][c]=nq;  
                }
            }
        }      
        tag[last][id]=1;  
    }    
    void dfs(int u) 
    { 
        st[u]=++dfn; 
        for(int i=hd[u];i;i=nex[i]) 
        {
            int v=to[i]; 
            dfs(v);   
            tag[u][0]|=tag[v][0]; 
            tag[u][1]|=tag[v][1]; 
            tag[u][2]|=tag[v][2];  
        }
        ed[u]=dfn;  
    }           
    int main() 
    { 
        // setIO("input"); 
        last=tot=1;
        int i,j,len,cor; 
        for(scanf("%s",S+1),len=strlen(S+1),last=1,i=1;i<=len;++i) extend(S[i]-'a',0);   
        for(scanf("%s",S+1),len=strlen(S+1),last=1,i=1;i<=len;++i) extend(S[i]-'a',1);              
        for(scanf("%s",S+1),len=strlen(S+1),last=1,i=1;i<=len;++i) extend(S[i]-'a',2);    
        for(i=2;i<=tot;++i) add(pre[i],i);          
        dfs(1); 
        if(tag[last][0]&&tag[last][1])  
            ans=len-1;                                    
        for(i=1;i<=tot;++i)  if(st[i]>=st[last]&&ed[i]<=ed[last])  dp[i]=-inf,is[i]=1;  
        dp[last]=len-1;  
        for(i=1;i<=tot;++i)  for(j=0;j<26;++j) if(ch[i][j])  ++deg[ch[i][j]];     
        for(i=1;i<=tot;++i)  if(!deg[i]) que.push(i);       
        while(!que.empty()) 
        {  
            int u=que.front();que.pop();  
            for(int j=0;j<26;++j)  
            {
                int v=ch[u][j]; 
                if(!v) continue;                       
                if(!is[v]) dp[v]=max(dp[v],dp[u]+1);   
                --deg[v];  
                if(!deg[v]) que.push(v); 
            }
        }
        for(i=1;i<=tot;++i)  if(tag[i][0]&&tag[i][1]) ans=max(ans,dp[i]); 
        printf("%d
    ",ans);  
        return 0;
    }
    

      

  • 相关阅读:
    python 学习笔记(四)(流程控制)
    python 写斐波那契数列
    python 部分术语对照表
    python 学习笔记(三)(对前两节的补充)
    python # -*- coding: utf-8 -*-
    写出更好的 JavaScript 条件语句
    PHP消息队列实现及应用
    VUE3.0 路由去掉#号
    php设计模式
    workerman 可能需要用到的函数
  • 原文地址:https://www.cnblogs.com/guangheli/p/12122682.html
Copyright © 2011-2022 走看看