ZOJ3784 String of Infinity(AC自动机&&强连通分量)
题意:给你n个禁止串,然后你只能用字符表的前m个字符去写一个无限长的串,要求是不能包含禁止串,而且串在后面不能出现循环
比赛的时候想的是先建一个自动机,然后将自动机确定化,不能到达的状态全部弄出来。但是对于剩下的状态就卡住了,我怎么才能知道这些状态会构成循环呢?后来看了别人的代码,看到了强连通分量,我就恍然大悟了。其实只需要对剩下的未确定的状态,根据转移边建图,然后跑一次强连通分量。
这么做的效果就是将原图剩下的状态缩成了一个DAG,我们每次只能由根结点往下走,我们必然需要停留在某个强连通分量里,不然的话我走到拓扑序最后的分量就不能再走了(或者说走到拓扑序最后的话,就只能在那个强连通分量沿着分量内的边走“自环”)。如果这个强连通分量是一个环的话,那么显然我们停留在这个强连通分量里的话就会有循环节。所以问题转化为是否存在一个强连通分量它不是一个环。判断方法就是维系一个大小为n的强连通分量至少需要n条边,只要强连通分量内的边大于n,它就不是一个自环。
#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;
}
ZOJ3784 String of Infinity(AC自动机&&强连通分量)的更多相关文章
- Searching the String ZOJ - 3228 AC自动机查询升级版
题意:先给你一个不超过1000000长度的大串s:接下来输入一个n代表接下来输入的小串个数,小串长度不超过6. 小串分两种类型0和1类型. 0类型表示小串在大串中的最大匹配个数就是常规的AC自动机的做 ...
- @noi.ac - 506@ 强连通分量
目录 @description@ @solution@ @accepted code@ @details@ @description@ 有一天你学了一个叫能求出有向图中所有的强连通分量的算法,你决定将 ...
- ZOJ3784 String of Infinity 高大上的AC自动机 数据原来这么水啊!不算输入输出只有5-7行
找给定s集合里面word全部是同一个字符的,这样的word有几个,如果数量<m就yes,否则就no.#include<iostream> #include<cstring> ...
- LA 4670 Dominating Patterns (AC自动机)
题意:给定n个字符串和一个文本串,查找哪个字符串出现的次数的最多. 析:一匹配多,很明显是AC自动机.只需要对原来的进行修改一下,就可以得到这个题的答案, 计算过程中,要更新次数,并且要映射字符串.如 ...
- 【Codeforces710F】String Set Queries (强制在线)AC自动机 + 二进制分组
F. String Set Queries time limit per test:3 seconds memory limit per test:768 megabytes input:standa ...
- AC自动机---Searching the String
ZOJ 3228 题目网址:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=16401 Description Little ...
- ZOJ 3228 Searching the String(AC自动机)
Searching the String Time Limit: 7 Seconds Memory Limit: 129872 KB Little jay really hates to d ...
- 【XSY3320】string AC自动机 哈希 点分治
题目大意 给一棵树,每条边上有一个字符,求有多少对 \((x,y)(x<y)\),满足 \(x\) 到 \(y\) 路径上的边上的字符按顺序组成的字符串为回文串. \(1\leq n\leq 5 ...
- Codeforces963C Frequency of String 【字符串】【AC自动机】
题目大意: 给一个串s和很多模式串,对每个模式串求s的一个最短的子串使得这个子串中包含至少k个该模式串. 题目分析: 均摊分析,有sqrt(n)种长度不同的模式串,所以有关的串只有msqrt(n)种. ...
随机推荐
- Python核心编程--学习笔记--5--数字
本章的主题是Python中的数字,这里详细介绍每一种数字类型,它们适用的各种运算符,以及用于处理数字的内建函数.在本章的末尾简单介绍了几个标准库中用于处理数字的模块. 1 数字类型 数字:标量贮存,可 ...
- C#模糊查询绑定datagridview
private CollectionViewSource wgdData = new CollectionViewSource(); private DataTable Ds_wgd { get { ...
- 禁止生成文件Thumbs.db
Thumbs.db是一个用于Microsoft Windows XP.Windows7 或 mac os x缓存Windows Explorer的缩略图的文件.Thumbs.db保存在每一个包含图片或 ...
- Redbean:入门(一) - 增删改查
<?php require_once 'rb.php'; $tableName = "link"; //链接数据库 R::setup("mysql:host=loc ...
- PHY
Linux 下smi/mdio总线通信 韩大卫@吉林师范大学 下面代码描述了在用户层访问smi/mdio总线, 读写phy芯片寄存器的通用代码.Linux内核2.6以上通用. 将下面代码编译后,将可执 ...
- 主要从架构上来做优化,负载均衡、CDN、静态化、数据库的水平切割和纵向切割、读写分离、分布式缓存着手
语言知识一种工具,甚至技术本身也只是一种工具,本身并不值钱,关键在于用于何种行业,产生了什么价值. 但从语言来看,我个人更喜欢php,然后是C#,然后是java从框架而言,先是java,然后C#,再次 ...
- Ajaxadr ajax跨域请求crossdomain
最近工作需要用到ajax跨域请求参数,网上找很很久,最终得到解决之道.分享一下吧,希望能帮到各位 也许你已经发现在浏览器直接敲路径能获得对方提供接口的参数,而一到项目中Ajax请求却老是失败.原因是, ...
- 分布式架构--第一篇--项目拆分(maven命令生成多模块项目)
预览生成的项目结构: ying-yue-parent // 顶级总编译控制模块 ying-yue-lib // jar模块 ying-yue-model // 模型对象模块 ying-yue-dao ...
- Android -- 分享功能和打开指定程序
打开指定程序 Intent intent ...
- 关于四则运算的代码debug测试
1.首先检测题目是否能为负数,0? 截图: 总结:如图所示出题数目为0的时候,并没提示重新输入,而是输出空白,而当输出题目为负数的时候系统提示错误,并且提示终止 2.检测操作值得范围: 总结:当操 ...