https://vjudge.net/problem/HDU-6208

首先可以知道最长那个串肯定是答案

然后,相当于用n - 1个模式串去匹配这个主串,看看有多少个能匹配。

普通kmp的话,每次都要O(mxLen)的复杂度肯定不行。考虑AC自动机,不说这个算法了都懂。

大概就是,询问主串的时候用Fail指针快速转移到LCP,然后就可以用字典树快速判断其是否一个模式串

可以知道判断过的可以标记下,不需要再判断了(听说很多人TLE在这里了,比赛的时候写歪了也TLE)

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
const int maxn = 6e5 + , N = ;
struct node {
int flag;
struct node *Fail; //失败指针,匹配失败,跳去最大前后缀
struct node *pNext[N];
} tree[maxn];
int t; //字典树的节点
struct node *create() { //其实也只是清空数据而已,多case有用,根是0号顶点、
struct node *p = &tree[t++];
p->flag = ;
p->Fail = NULL;
for (int i = ; i < N; i++) {
p->pNext[i] = NULL;
}
return p;
}
void toinsert(struct node **T, char str[], int be, int en) {
struct node *p = *T;
if (p == NULL) {
p = *T = create();
}
for (int i = be; i <= en; i++) {
int id = str[i] - 'a';
if (p->pNext[id] == NULL) {
p->pNext[id] = create();
}
p = p->pNext[id];
}
p->flag++; //相同的单词算两次
}
struct node *que[maxn + ]; //这里的t是节点总数,字典树那里统计的,要用G++编译
void BuiltFail(struct node **T) {
//根节点没有失败指针,所以都是需要特判的
//思路就是去到爸爸的失败指针那里,找东西匹配,这样是最优的
struct node *p = *T; //用个p去代替修改
struct node *root = *T;
if (p == NULL) return ;
//树上bfs,要更改的是p->pNext[i]->Fail
int head = , tail = ;
que[tail++] = root;
while (head < tail) {
p = que[head]; //p取出第一个元素 ★
for (int i = ; i < N; i++) { //看看存不存在这个节点
if (p->pNext[i] != NULL) { //存在的才需要管失败指针。
if (p == root) { //如果爸爸是根节点的话,根节点没有失败指针
p->pNext[i]->Fail = root; //指向根节点
} else {
struct node *FailNode = p->Fail; //首先找到爸爸的失败指针
while (FailNode != NULL) {
if (FailNode->pNext[i] != NULL) { //存在
p->pNext[i]->Fail = FailNode->pNext[i];
break;
}
FailNode = FailNode->Fail; //回溯,根节点的fail是NULL
}
if (FailNode == NULL) { //如果还是空,那么就指向根算了
p->pNext[i]->Fail = root;
}
}
que[tail++] = p->pNext[i]; //这个id是存在的,入队bfs
}
}
head++;
}
}
int searchAC(struct node *T, char str[], int be, int en) {
int ans = ;
struct node *p = T;
struct node *root = T;
if (p == NULL) return ;
for (int i = be; i <= en; i++) { //遍历主串中的每一个字符
int id = str[i] - 'a';
p = p->pNext[id]; //去到这个节点,虚拟边也建立起来了,所以一定存在。
struct node *temp = p; //p不用动,下次for就是指向这里就OK,temp去找后缀串
//什么叫找后缀串?就是,有单词 she,he 串***she,那么匹配到e的时候,she统计成功
//这个时候,就要转移去到he那里,也把he统计进去。也就是找等价态
while (temp != root && temp->flag != -) { //root没失败指针
if (temp->flag > ) {
ans += temp->flag;
}
temp->flag = -; //标记,,他们卡在这里吗
temp = temp->Fail;
}
}
return ans;
}
char str[maxn];
void work() {
t = ;
int n;
scanf("%d", &n);
struct node * T = NULL;
int ansbe = , ansen = , anslen = ;
int pre = ;
for (int i = ; i <= n; ++i) {
scanf("%s", str + pre);
int tlen = strlen(str + pre);
pre += tlen;
if (tlen > anslen) {
anslen = tlen;
ansbe = pre - tlen;
ansen = pre - ;
}
toinsert(&T, str, pre - tlen, pre - );
}
// printf("%s\n", now + 1);
BuiltFail(&T);
if (searchAC(T, str, ansbe, ansen) == n) {
for (int i = ansbe; i <= ansen; ++i) {
printf("%c", str[i]);
}
printf("\n");
} else printf("No\n");
} int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
int t;
scanf("%d", &t);
while (t--) work();
return ;
}

然后生气了还是sam吧

对最长的串建立sam

对于每一个串是否其子串,可以O(lensub)判断。

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
const int maxn = 1e5 + , N = ;
struct SAM {
int mxCnt[maxn << ], son[maxn << ][N], fa[maxn << ];
int root, last, DFN, t;
int create() {
++t;
mxCnt[t] = fa[t] = NULL;
for (int i = ; i < N; ++i) son[t][i] = NULL;
return t;
}
void init() {
++DFN;
t = , root = ;
last = create();
}
void addChar(int x, int _pos, int id) {
int p = last;
int np = create();
last = np;
mxCnt[np] = mxCnt[p] + ;
for (; p && son[p][x] == NULL; p = fa[p]) son[p][x] = np;
if (p == NULL) {
fa[np] = root;
return;
}
int q = son[p][x];
if (mxCnt[q] == mxCnt[p] + ) {
fa[np] = q;
return;
}
int nq = create();
for (int i = ; i < N; ++i) son[nq][i] = son[q][i];
fa[nq] = fa[q], mxCnt[nq] = mxCnt[p] + ;
fa[q] = nq, fa[np] = nq;
for (; p && son[p][x] == q; p = fa[p]) son[p][x] = nq;
}
bool is(string &str, int tt) {
int p = root;
for (int i = ; i < tt; ++i) {
if (son[p][str[i] - 'a']) {
p = son[p][str[i] - 'a'];
} else return false;
}
return true;
}
} sam;
string str[maxn];
int tt[maxn];
char liu[maxn];
void work() {
sam.init();
int n;
scanf("%d", &n);
int id = , len = ;
for (int i = ; i <= n; ++i) {
scanf("%s", liu);
str[i] = string(liu);
tt[i] = strlen(str[i].c_str());
if (len < tt[i]) {
len = tt[i];
id = i;
}
}
for (int i = ; i < len; ++i) {
sam.addChar(str[id][i] - 'a', i, );
}
for (int i = ; i <= n; ++i) {
if (i == id) continue;
if (!sam.is(str[i], tt[i])) {
printf("No\n");
return;
}
}
printf("%s\n", str[id].c_str());
} int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
int t;
scanf("%d", &t);
while (t--) work();
return ;
}

HDU - 6208 The Dominator of Strings HDU - 6208 AC自动机 || 后缀自动机的更多相关文章

  1. hdu 6208 The Dominator of Strings【AC自动机】

    hdu 6208 The Dominator of Strings[AC自动机] 求一个串包含其他所有串,找出最长串去匹配即可,但是匹配时要对走过的结点标记,不然T死QAQ,,扎心了.. #inclu ...

  2. HDU 6208 The Dominator of Strings(AC自动机)

    The Dominator of Strings Time Limit: 3000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java ...

  3. HDU 6208 The Dominator of Strings 后缀自动机

    The Dominator of Strings Time Limit: 3000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java ...

  4. 2017 ACM/ICPC Asia Regional Qingdao Online 1003 The Dominator of Strings hdu 6208

    The Dominator of Strings Time Limit: 3000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java ...

  5. HDU 6208 The Dominator of Strings【AC自动机/kmp/Sunday算法】

    Problem Description Here you have a set of strings. A dominator is a string of the set dominating al ...

  6. The Dominator of Strings HDU - 6208(ac自动机板题)

    题意: 就是求是否有一个串 是其它所有串的母串 解析: 把所有的串都加入到trie数中  然后用最长的串去匹配就好了 emm..开始理解错题意了...看成了只要存在一个串是另一个的母串就好.. 然后输 ...

  7. HDU 6208 The Dominator of Strings ——(青岛网络赛,AC自动机)

    最长的才可能成为答案,那么除了最长的以外全部insert到自动机里,再拿最长的去match,如果match完以后cnt全被清空了,那么这个最长串就是答案.事实上方便起见这个最长串一起丢进去也无妨,而且 ...

  8. HDU 4622 Reincarnation(后缀自动机)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4622 [题目大意] 给出一个长度不超过2000的字符串,有不超过10000个询问,问[L,R]子串 ...

  9. hdu6208 The Dominator of Strings

    地址: 题目: The Dominator of Strings Time Limit: 3000/3000 MS (Java/Others)    Memory Limit: 65535/32768 ...

随机推荐

  1. 福大软工1816 · 第五次作业 - 结对作业2_EXE图片_备用

    1_每日推荐界面.png 2_论文搜索界面.png 2_论文搜索界面_搜索功能.png 3_流行趋势_十大热词排名统计图.png 4_人物界面.png 5_我的收藏界面.png 6_设置界面.png ...

  2. .net core 2.0 jwt身份认证系统

    经历了很久,.net core 2.0 终于发布了! 之前一直用的core 1.1,升级了2.0后发现认证的机制(Auth)发生了比较大的变化,在1.1中认证配置是在Configure中完成,而在2. ...

  3. 运维利器:钉钉机器人脚本告警(Linux Shell 篇)

    写在前面的话 目前换了几家公司,且最近几家都是以钉钉作为公司 OA 聊天工具,总的来说还是很不错的.最近去了新公司,由于公司以前没有运维,所以监控,做自动化等方面都没有实施,恰逢这个机会把最近做的关于 ...

  4. iOS开发进制转换

    1.十进制转换为二进制 /** 十进制转换为二进制 @param decimal 十进制数 @return 二进制数 */ + (NSString *)getBinaryByDecimal:(NSIn ...

  5. laravel安装[转https://laravelacademy.org/post/9528.html]

    Laravel 框架对PHP版本和扩展有一定要求,不过这些要求 Laravel Homestead 都已经满足了,不过如果你没有使用 Homestead 的话(那真是一件很遗憾的事情),有必要了解下这 ...

  6. Pyinstaller打包matplotlib.pyplot画图时提示无法找到Qt插件的解决办法

    This application failed to start because it could not find or load the Qt platform plugin "wind ...

  7. 【转】在Asp.net前台和后台弹出提示框

    源地址:http://blog.sina.com.cn/s/blog_5200dd680100mkk0.html

  8. left jion on和where条件的区别

    1.on是在生成临时表时()起作用,而且不管on中的条件是否为真,都会返回(left join)左边所有的数据,如果不匹配也是返回空. 2.where 是在生成了临时表后,再对表进行过滤 个人理解:先 ...

  9. 第一章:初识JAVA

    一:计算机语言发展史 机器语言:典型的二进制文件和计算机交流. 汇编语言: 通过大量的标识符表示一些基本操作来和计算机做交流. 高级语言:通过常见的英语指令来编写程序,完成沟通 常见高级语言 Java ...

  10. freemarker常用标签解释三

    1 date,time,datetime 日期,时间,时间日期 <#assign test1 = "10/25/1995"?date("MM/dd/yyyy&quo ...