【[POI2000]病毒】

\(Ac\)自动机好题了

这个题要求我们一直无法匹配到结束标记,所以我们直接在\(trie\)图上找到一个环,这个环可以被根节点到达,之后还没有结束标记

发现自己不会\(dfs\)找环,于是直接莽上\(tarjan\)

之后一直写挂各种\(sb\)

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#define re register
#define LL long long
#define maxn 30005
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
struct E{int v,nxt;}e[maxn<<4];
int head[maxn];
int n,m,cnt,top,tot,p,num,mid;
char S[maxn];
int son[maxn][2],fail[maxn],flag[maxn];
int dfn[maxn],low[maxn],f[maxn],st[maxn],col[maxn],d[maxn],vis[maxn];
inline void ins()
{
    scanf("%s",S+1);
    int len=strlen(S+1),now=0;
    for(re int i=1;i<=len;i++)
    {if(!son[now][S[i]-'0']) son[now][S[i]-'0']=++cnt;now=son[now][S[i]-'0'];}
    flag[now]=1;
}
inline void Build()
{
    std::queue<int> q;
    for(re int i=0;i<2;i++) if(son[0][i]) q.push(son[0][i]);
    while(!q.empty())
    {
        int k=q.front();q.pop();
        flag[k]|=flag[fail[k]];
        for(re int i=0;i<2;i++)
        if(son[k][i]) fail[son[k][i]]=son[fail[k]][i],q.push(son[k][i]);
            else son[k][i]=son[fail[k]][i];
    }
}
void tarjan(int x)
{
    if(flag[x]) return;
    f[x]=1,st[++top]=x,dfn[x]=low[x]=++tot;
    for(re int i=0;i<2;i++)
    {
        if(flag[son[x][i]]) continue;
        if(!dfn[son[x][i]]) tarjan(son[x][i]),low[x]=min(low[x],low[son[x][i]]);
        else if(f[son[x][i]]) low[x]=min(low[x],dfn[son[x][i]]);
    }
    if(dfn[x]==low[x])
    {
        ++p;int t=0;
        do {mid=st[top--];f[mid]=0,t++,col[mid]=p;}while(x!=mid);
        d[p]=t;
    }
}
inline void add_edge(int x,int y){e[++num].v=y,e[num].nxt=head[x],head[x]=num;}
int dfs(int x)
{
    if(d[x]>1) return 1;
    int ff=0;
    vis[x]=1;
    for(re int i=head[x];i;i=e[i].nxt)
    if(!vis[e[i].v]) ff|=dfs(e[i].v);
    return ff;
}
int main()
{
    scanf("%d",&n);
    for(re int i=1;i<=n;i++) ins();Build();
    for(re int i=0;i<=cnt;i++) if(!dfn[i]) tarjan(i);
    for(re int i=0;i<=cnt;i++)
        for(re int j=0;j<2;j++) if(col[son[i][j]]!=col[i]) add_edge(col[i],col[son[i][j]]);
    for(re int i=0;i<=cnt;i++)
        for(re int j=0;j<2;j++)
            if(son[i][j]==i) d[col[i]]++;
    vis[0]=1;
    if(dfs(col[0])) puts("TAK");else puts("NIE");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/asuldb/p/10207921.html