AC自动机+有向拓扑判环 Taboo Kattis - taboo

Taboo Kattis - taboo

题意:给一些01串,然后问有没有串没有包含这些01串的。如果有的话就输出,如果为无限长的话,就输出-1

分析:题目看错。。。做了好久,心好痛

这个题就是AC自动机建图,bad点都处理好了(和之前DNA处理一模一样)。然后拓扑判断一下是不是有环,如果有的话就-1,否者就输出最长串就行了。输出可以用dfs直接来,当然也可以用优雅的树dp思想

#define LL long long
#define mem(a,b) memset(a,b,sizeof(a))

const int maxn = 2e5+10;
string s[maxn];
char ans[maxn];
const int sz=3;
int flag=0,ansnum=0,tt=0;
int G[maxn][2];
void addedge(int u,int v,int w)
{
    G[u][w]=v;
}
struct Trie
{
    int next[maxn][3],fail[maxn],ed[maxn];
    int root,L;
    int newnode()
    {
        for(int i=0;i<2;i++)
            next[L][i]=-1;
        ed[L++]=0;
        return L-1;
    }
    void init()
    {
        mem(fail,0);mem(ed,0);mem(in,0);
        L=0;
        root=newnode();
    }
    void sert(string buf)
    {
        int len=buf.length();
        int now=root;
        for(int i=0;i<len;i++)
        {
            if(next[now][buf[i]-'0']==-1)
                next[now][buf[i]-'0']=newnode();
            now=next[now][buf[i]-'0'];
        }
        ed[now]++;
    }
    void buildfail()
    {
        queue<int> Q;
        fail[root]=root;
        for(int i=0;i<2;i++)
            if(next[root][i] == -1)
                  next[root][i]=root;
            else{
                fail[next[root][i]]=root;
                Q.push(next[root][i]);
            }
        while(!Q.empty())
        {
            int now=Q.front();
            Q.pop();
            if(ed[fail[now]]) ed[now]=1;
            for(int i=0;i<2;i++)
                if(next[now][i]==-1)
                    next[now][i]=next[fail[now]][i];
                else{
                    fail[next[now][i]]=next[fail[now]][i];
                    Q.push(next[now][i]);
                }
        }
    }
    int in[maxn],vis[maxn],inq[maxn],in2[maxn];
    void dfs2(int now)
    {
        for(int i=0;i<2;i++)
        {
            int j=next[now][i];
            if(ed[j]) continue;
            in[j]++;in2[j]++;
            if(in[j]==1) dfs2(j);
        }
    }
    bool topo()//拓扑判环
    {
        mem(in,0);mem(inq,0);mem(vis,0);
        dfs2(0);
        queue<int> q;while(!q.empty()) q.pop();
        if(in[0]) return 1;
        q.push(0);
        while(!q.empty()){
            int now=q.front();q.pop();
            for(int i=0;i<2;i++)
            {
                int j=next[now][i];
                if(ed[j]) continue;
                in[j]--;
                vis[j]=1;
                if(!in[j]) {inq[j]=1;q.push(j);}
            }
        }
        for(int i=0;i<L;i++)
        {
            if(inq[i]!=vis[i]) return true;
        }
        return false;
    }
    int dp[maxn],to[maxn],maxx=0;
    void dfs3(int now,int num)//求串的最大长度
    {
        if(num==maxx) {tt=1;return ;}
        for(int i=0;i<2;i++)
        {
            int j=next[now][i];
            if(ed[j]) continue;
            dfs3(j,num+1);
            if(tt){
                ans[num]=i+'0';return ;
            }
        }
    }
    void dfs5(int now,int num)//找最大串
    {
        maxx=max(num,maxx);
        for(int i=0;i<2;i++)
        {
            int j=next[now][i];
            if(ed[j]) continue;
            dfs5(j,num+1);
        }
    }
    void query()
    {
        if(topo())
        {
            printf("-1");
            return ;
        }
        mem(dp,0);mem(to,0);
        queue<int> q; while(!q.empty()) q.pop();q.push(0);
        dfs5(0,0);
        dfs3(0,0);
    printf("%s\n",ans);
}
};
Trie ac;
void init()
{
    mem(ans,'\0');flag=0;tt=0;ansnum=0;
}
int main()
{
    int n;
    scanf("%d",&n);
    ac.init();
    init();
    for(int i=0;i<n;i++){
        cin>>s[i];
        ac.sert(s[i]);
    }
    ac.buildfail();
    ac.query();
    return 0;
}

树dp输出

 void dfs3(int now)
    {
        for(int i=0;i<2;i++)
        {
            int j=next[now][i];
            if(ed[j]) continue;
            dfs3(j);
            to[now]=max(to[now],to[j]+1);
            if(to[j]+dp[now]+1 == maxx)
                addedge(now,j,i);
        }
    }
    void query()
    {
        if(topo())
        {
            printf("-1");
            return ;
        }
        mem(dp,0);mem(to,0);
        queue<int> q; while(!q.empty()) q.pop();q.push(0);
        while(!q.empty())
        {
            int now=q.front();q.pop();
            for(int i=0;i<2;i++){
                int j=next[now][i];
                if(ed[j]) continue;
                if(dp[j]<dp[now]+1)
                    dp[j]=dp[now]+1;
                in2[j]--;
                if(!in2[j]) {q.push(j);maxx=max(maxx,dp[j]);}
            }
        }
        mem(G,-1);
        dfs3(0);
        int u=0;
        while(dp[u]!=maxx)
        {
            if(G[u][0]!=-1)
            {
                printf("0");
                u=G[u][0];
            }
            else {
                printf("1");
                u=G[u][1];
            }
        }
        printf("\n");
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值