BZOJ 2938 [Poi2000]病毒

题目链接

权限题不放题目描述了

思路

建好AC自动机,用DFS判环。

代码

#include <cstdio>
#include <cstring>

const int maxn=30000;

struct ac_automaton
{
  int son[maxn+10][2],cnt,fail[maxn+10],danger[maxn+10],q[maxn+10],head,tail,vis[maxn+10],fuck[maxn+10];

  inline int clear()
  {
    memset(son,0,sizeof son);
    memset(fail,0,sizeof fail);
    memset(danger,0,sizeof danger);
    cnt=0;
    return 0;
  }

  inline int ins(char* s)
  {
    int now=0,ls=strlen(s);
    for(register int i=0; i<ls; ++i)
      {
        if(!son[now][s[i]-'0'])
          {
            son[now][s[i]-'0']=++cnt;
          }
        now=son[now][s[i]-'0'];
      }
    danger[now]=1;
    return 0;
  }

  inline int build()
  {
    head=tail=0;
    for(register int i=0; i<=1; ++i)
      {
        if(son[0][i])
          {
            q[++tail]=son[0][i];
            fail[son[0][i]]=0;
          }
      }
    while(head!=tail)
      {
        int u=q[++head];
        for(register int i=0; i<=1; ++i)
          {
            if(son[u][i])
              {
                int now=fail[u];
                while(now&&(!son[now][i]))
                  {
                    now=fail[now];
                  }
                fail[son[u][i]]=son[now][i];
                if(danger[fail[son[u][i]]])
                  {
                    danger[son[u][i]]=1;
                  }
                q[++tail]=son[u][i];
              }
            else
              {
                son[u][i]=son[fail[u]][i];
              }
          }
      }
    return 0;
  }

  int dfs(int now)
  {
    vis[now]=1;
    for(register int i=0; i<=1; ++i)
      {
        if(vis[son[now][i]])
          {
            return 1;
          }
        if(danger[son[now][i]]||fuck[son[now][i]])
          {
            continue;
          }
        fuck[son[now][i]]=1;
        if(dfs(son[now][i]))
          {
            return 1;
          }
      }
    vis[now]=0;
    return 0;
  }
};

char s[maxn+10];
int n;
ac_automaton ac;

int main()
{
  scanf("%d",&n);
  ac.clear();
  for(register int i=1; i<=n; ++i)
    {
      scanf("%s",s);
      ac.ins(s);
    }
  ac.build();
  puts(ac.dfs(0)?"TAK":"NIE");
  return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值