ZOJ3784 String of Infinity(AC自动机&&强连通分量)
题意:给你n个禁止串,然后你只能用字符表的前m个字符去写一个无限长的串,要求是不能包含禁止串,而且串在后面不能出现循环
比赛的时候想的是先建一个自动机,然后将自动机确定化,不能到达的状态全部弄出来。但是对于剩下的状态就卡住了,我怎么才能知道这些状态会构成循环呢?后来看了别人的代码,看到了强连通分量,我就恍然大悟了。其实只需要对剩下的未确定的状态,根据转移边建图,然后跑一次强连通分量。
这么做的效果就是将原图剩下的状态缩成了一个DAG,我们每次只能由根结点往下走,我们必然需要停留在某个强连通分量里,不然的话我走到拓扑序最后的分量就不能再走了(或者说走到拓扑序最后的话,就只能在那个强连通分量沿着分量内的边走“自环”)。如果这个强连通分量是一个环的话,那么显然我们停留在这个强连通分量里的话就会有循环节。所以问题转化为是否存在一个强连通分量它不是一个环。判断方法就是维系一个大小为n的强连通分量至少需要n条边,只要强连通分量内的边大于n,它就不是一个自环。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | #pragma warning(disable:4996) #include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <set> #include <vector> #include<queue> #include<stack> #include <cmath> using namespace std; #define maxn 210000 #define ll long long int n, m; struct Trie{ Trie *fail, *go[26]; bool ter; bool flag; void init(){ memset (go, 0, sizeof (go)); fail = NULL; ter = false ; flag = false ; } }pool[maxn], *root; int tot; void insert( char *c){ int len = strlen (c); Trie *p = root; for ( int i = 0; i < len; i++){ if (p->go[c[i] - 'a' ] != 0) p = p->go[c[i] - 'a' ]; else { pool[tot].init(); p->go[c[i] - 'a' ] = &pool[tot++]; p = p->go[c[i] - 'a' ]; } } p->ter = true ; } void getFail() { queue<Trie*> que; que.push(root); root->fail = NULL; while (!que.empty()){ Trie *temp = que.front(); que.pop(); Trie *p = NULL; for ( int i = 0; i < m; i++){ if (temp->go[i] != NULL){ if (temp == root) temp->go[i]->fail = root; else { p = temp->fail; while (p != NULL){ if (p->go[i] != NULL){ temp->go[i]->fail = p->go[i]; break ; } p = p->fail; } if (p == NULL) temp->go[i]->fail = root; } que.push(temp->go[i]); } } } } bool ddfs(Trie *p){ if (p == root||p==NULL) return false ; if (p->flag == true ) return p->ter; p->ter |= ddfs(p->fail); p->flag = true ; return p->ter; } int pre[maxn], low[maxn], sccno[maxn],siz[maxn]; int sta[maxn],st; int dfs_clock; int scc_cnt; int siz2[maxn]; void dfs( int u){ low[u] = pre[u] = ++dfs_clock; sta[++st] = u; for ( int i = 0; i < m; i++){ Trie *p = pool[u].go[i]; if (p->ter) continue ; int v = p - pool; if (!pre[v]){ dfs(v); low[u] = min(low[u], low[v]); } else if (!sccno[v]){ low[u] = min(low[u], pre[v]); } } if (low[u] == pre[u]){ ++scc_cnt; while (1){ int x = sta[st--]; sccno[x] = scc_cnt; siz[scc_cnt]++; if (x == u) break ; } } } void find_scc() { memset (siz, 0, sizeof (siz)); memset (sccno, 0, sizeof (sccno)); memset (low, 0, sizeof (low)); memset (pre, 0, sizeof (pre)); st = dfs_clock = 0; scc_cnt = 0; for ( int i = 0; i < tot; i++){ if (pool[i].ter) continue ; if (!pre[i]) dfs(i); } } char str[1500]; int main() { int T; cin >> T; while (T--) { cin >> n >> m; tot = 0; root = &pool[tot++]; root->init(); for ( int i = 0; i < n; i++){ scanf ( "%s" , str); insert(str); } getFail(); for ( int i = 0; i < tot; i++) ddfs(&pool[i]); for ( int i = 0; i < tot; i++){ Trie *p = &pool[i]; for ( int k = 0; k < m; k++){ if (p->go[k] == NULL){ Trie *temp = p; temp = temp->fail; while (temp != NULL){ if (temp->go[k] != NULL) { p->go[k] = temp->go[k]; break ; } temp = temp->fail; } if (temp == NULL) p->go[k] = root; } } } find_scc(); memset (siz2, 0, sizeof (siz2)); for ( int i = 0; i < tot; i++){ if (pool[i].ter) continue ; for ( int j = 0; j < m; j++){ int k = pool[i].go[j] - pool; if (sccno[k] == sccno[i]){ siz2[sccno[k]]++; } } } bool flag = false ; for ( int i = 1; i <= scc_cnt; i++){ if (siz2[i]>siz[i]){ flag = true ; break ; } } if (flag) puts ( "Yes" ); else puts ( "No" ); } return 0; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,携手博客园推出1Panel与Halo联合会员
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次 .NET某固高运动卡测试 卡慢分析
· 微服务架构学习与思考:微服务拆分的原则
· 记一次 .NET某云HIS系统 CPU爆高分析
· 如果单表数据量大,只能考虑分库分表吗?
· 一文彻底搞懂 MCP:AI 大模型的标准化工具箱
· 博客园2025新款「AI繁忙」系列T恤上架
· Avalonia跨平台实战(二),Avalonia相比WPF的便利合集(一)
· C# LINQ 快速入门实战指南,建议收藏学习!
· Redis实现高并发场景下的计数器设计
· 上周热点回顾(4.7-4.13)