bzoj 2938 AC自动机

根据题意建出trie图,代表单词的点不能走,直接或间接指向它的点也不能走。这样的话如果能在图中找到一个环的话就是TAK,否则是NIE。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 #define N 30005
 7 using namespace std;
 8 int n;bool flag;
 9 int ch[N][2];
10 bool yes[N][2];
11 char s[N];int cnt;
12 bool ok[N];
13 void inn()
14 {
15     int now=0;
16     int l=strlen(s);
17     for(int i=0;i<l;i++)
18     {
19         if(!ch[now][s[i]-‘0‘])ch[now][s[i]-‘0‘]=++cnt,yes[now][s[i]-‘0‘]=1;
20         now=ch[now][s[i]-‘0‘];
21     }
22     ok[now]=1;
23 }
24 int f[N];
25 int vis[N],in[N];
26 queue<int>q;
27 void dfs(int x)
28 {
29 //    cout<<x<<endl;
30 //    cout<<in[1]<<"SS"<<endl;
31     vis[x]=1;in[x]=1;
32     for(int i=0;i<2;i++)
33     {
34         if(!vis[ch[x][i]])
35         {
36             if(!ok[ch[x][i]])
37             {
38                 dfs(ch[x][i]);
39             }
40         }
41         else if(in[ch[x][i]])
42         {
43             flag=1;
44         }
45     }
46     in[x]=0;
47 }
48 bool fail()
49 {
50     for(int i=0;i<2;i++)if(ch[0][i])q.push(ch[0][i]);
51     while(!q.empty())
52     {
53         int tmp=q.front();q.pop();
54         for(int i=0;i<2;i++)
55         {
56             int u=ch[tmp][i];
57             if(!u)
58             {
59                 ch[tmp][i]=ch[f[tmp]][i];continue;
60             }
61             f[u]=ch[f[tmp]][i];
62             if(ok[f[u]])ok[u]=1;
63             q.push(u);
64         }
65     }
66     dfs(0);
67     if(flag)return 1;
68     return 0;
69 }
70 int main()
71 {
72     scanf("%d",&n);
73     for(int i=1;i<=n;i++)
74     {
75         scanf("%s",s);inn();
76     }
77     //cout<<f[5]<<endl;
78     if(fail())puts("TAK");
79     else puts("NIE");
80     return 0;
81 }
时间: 2024-10-08 17:06:45

bzoj 2938 AC自动机的相关文章

bzoj 2434 ac自动机

ac自动机中,如果以trie中的节点为节点,(fail[i],i)为边,可以建立一颗树,该树有如下特点:“节点u是节点v的祖先 当且仅当 u代表的字符串是v代表的字符串的一个后缀”.(u代表的字符串是由根节点到u路径上所有的边代表的字符顺次组合成的,我们记作str(u)). 本题中的每一个P都对应trie中的一个节点,所以本题就是求str(b)中有多少个str(a)子串: 如果len(str(b))<len(str(a)),则为0 如果len(str(b))==len(str(a)),则判断a和

bzoj 1030 AC自动机+dp

代码: //先把给的单词建AC自动机并且转移fail,然后d[i][j]表示构造的文章到第i位时处在字典树的第j个节点的不包含单词的数量,最后用总的数量26^m //-d[m][0~sz]即可.其中不能走单词结尾的节点以及他们的fail.这里其实要把每个节点都连向他的26个后继,但是不连也没关系可以看作 //那些没出现的节点都转移成了0节点. #include<iostream> #include<cstdio> #include<cstring> #include&l

bzoj 3172 AC自动机

代码: //建好AC自动机后就是fail的转移了,数量是从底向上转移的所以用一个队列记录下来节点顺序然后转移val数组即可. #include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int MAXN=1000009; int node[MAXN][30],f[MAXN],val[MAXN],tr[209],sz,qq[MA

bzoj 2434 AC自动机+树状数组

2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 3493  Solved: 1909[Submit][Status][Discuss] Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽

bzoj 1559 AC自动机 + dp

思路:直接在状态图上跑dp,最后枚举一下42种一下的.. 这个枚举有点恶心. #include<bits/stdc++.h> #define LL long long #define ll long long #define fi first #define se second #define mk make_pair #define PII pair<int, int> #define y1 skldjfskldjg #define y2 skldfjsklejg using n

[BZOJ 3172] [Tjoi2013] 单词 【AC自动机】

题目链接:BZOJ - 3172 题目分析: 题目要求求出每个单词出现的次数,如果把每个单词都在AC自动机里直接跑一遍,复杂度会很高. 这里使用AC自动机的“副产品”——Fail树,Fail树的一个性质是,一个字符串出现的次数,就等于以它的结点为根的Fail树中的子树中所有结点的 Cnt 和. 所以把每个单词插入的时候每个字符都 ++Cnt ,在建 Fail 的时候将结点依次压入一个栈,最后再从栈顶开始弹栈,更新栈顶元素的 Fail 的 Cnt 值,这样就是自叶子节点向上更新了. 我开始写的时候

[BZOJ 3530] [Sdoi2014] 数数 【AC自动机+DP】

题目链接:BZOJ - 3530 题目分析 明显是 AC自动机+DP,外加数位统计. WZY 神犇出的良心省选题,然而去年我太弱..比现在还要弱得多.. 其实现在做这道题,我自己也没想出完整解法.. 就想出了个 O(l^3) 的做法: 完全按照数位统计的思想来,先统计长度不足 len 的数字的合法种类数,这个枚举开头,然后 AC 自动机 DP 一下,用 f[i][j] 表示到了第 i 位,在第 j 个节点上的合法数字个数.这样是 O(L^2). 然后长度等于 n 的部分,就按照数位统计,一位位向

bzoj 3172 后缀数组|AC自动机

后缀数组或者AC自动机都可以,模板题. /************************************************************** Problem: 3172 User: BLADEVIL Language: C++ Result: Accepted Time:424 ms Memory:34260 kb ****************************************************************/ //By BLADEVI

[BZOJ 1009] [HNOI2008] GT考试 【AC自动机 + 矩阵乘法优化DP】

题目链接:BZOJ - 1009 题目分析 题目要求求出不包含给定字符串的长度为 n 的字符串的数量. 既然这样,应该就是 KMP + DP ,用 f[i][j] 表示长度为 i ,匹配到模式串第 j 位的字符串个数,然后转移就是可以从第 j 位加上一个字符转移到另一个位置. 然而..我并没有写过KMP + DP,我觉得还是写AC自动机+DP比较简单..于是,尽管只有一个模式串,我还是写了AC自动机+DP. 然后就是建出AC自动机,f[i][j] 表示长度为 i ,走到节点 j 的字符串的个数.