http://acm.hdu.edu.cn/showproblem.php?pid=5510

想了很久队友叫我用ufs + kmp暴力过去了。

fa[x] = y表示x是y的子串,所以只有fa[x] == x才需要kmp一次。

那么这样的话,如果全部都不互为子串的话,复杂度还是爆咋的。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <string>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
#define X first
#define Y second
#define clr(u,v); memset(u,v,sizeof(u));
#define in() freopen("data.txt","r",stdin);
#define out() freopen("ans","w",stdout);
#define Clear(Q); while (!Q.empty()) Q.pop();
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const ll INF = 1e17;
const int inf = 0x3f3f3f3f;
const int maxn = + ;
int tonext[][maxn];
void get_next(char sub[], int tonext[], int lensub) {
int i = , j = ;
tonext[] = ;
while (i <= lensub) {
if (j == || sub[i] == sub[j]) {
tonext[++i] = ++j;
} else j = tonext[j];
}
}
int kmp(char str[], char sub[], int lenstr, int lensub, int tonext[]) {
int i = , j = ;
while (i <= lenstr) {
if (j == || str[i] == sub[j]) {
++i, ++j;
} else j = tonext[j];
if (j == lensub + ) return true;
}
return false;
}
char str[][maxn];
int len[];
int f;
int fa[maxn];
int tofind(int u) {
if (fa[u] == u) return u;
else return fa[u] = tofind(fa[u]);
}
void tomerge(int x, int y) {
x = tofind(x), y = tofind(y);
fa[y] = x;
}
void work() {
int n;
scanf("%d", &n);
for (int i = ; i <= n; ++i) {
scanf("%s", str[i] + );
len[i] = strlen(str[i] + );
get_next(str[i], tonext[i], len[i]);
fa[i] = i;
}
printf("Case #%d: ", ++f);
int ans = -;
for (int i = ; i <= n; ++i) {
for (int j = i - ; j >= ; --j) {
if (tofind(j) != j) continue;
if (kmp(str[i], str[j], len[i], len[j], tonext[j])) {
tomerge(i, j); //合并的方向,小的合并去大的
} else {
ans = i;
}
// if (kmp(str[j], str[i], len[j], len[i], tonext[i])) {
// tomerge(j, i);
// }
}
}
printf("%d\n", ans);
return;
} int main() {
#ifdef local
in();
#else
#endif
int t;
scanf("%d", &t);
while (t--) work();
return ;
}

有一个超时的AC自动机算法。复杂度O(T * n * lenstr * lenstr)

首先所有串buildFail

然后对于每一个串,爬Fail树。从后往前枚举

那么每个串跑一次Fail树的时候就能知道有多少个子串。成立的条件是子串个数 < i,则i位置成立。

如果后面的串使得匹配子串个数变大的话,那么是不影响的,说明在后面枚举的时候那个位置就应该是已经成立的了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <string>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
#define X first
#define Y second
#define clr(u,v); memset(u,v,sizeof(u));
#define in() freopen("2.h","r",stdin);
#define out() freopen("ans","w",stdout);
#define Clear(Q); while (!Q.empty()) Q.pop();
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const ll INF = 1e17;
const int inf = 0x3f3f3f3f;
char str[][ + ];
struct Node {
int flag, id;
struct Node *Fail;
struct Node *pNext[];
} tree[ + ];
int t;
struct Node * create() {
struct Node * p = &tree[t++];
p->flag = ;
p->Fail = NULL;
p->id = t - ;
for (int i = ; i < ; ++i) p->pNext[i] = NULL;
return p;
}
void toinsert(struct Node **T, char str[]) {
struct Node *p = *T;
if (p == NULL) p = *T = create();
for (int i = ; str[i]; ++i) {
int id = str[i] - 'a';
if (p->pNext[id] == NULL) {
p->pNext[id] = create();
}
p = p->pNext[id];
}
p->flag++;
}
struct Node * que[ + ];
void BuildFlag(struct Node **T) {
struct Node *p = *T;
struct Node *root = *T;
if (p == NULL) return ;
int head = , tail = ;
que[tail++] = root;
while (head < tail) {
p = que[head];
for (int i = ; i < ; ++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;
}
}
que[tail++] = p->pNext[i];
} else if (p == root) {
p->pNext[i] = root;
} else {
p->pNext[i] = p->Fail->pNext[i];
}
}
head++;
}
}
int vis[ + ], DFN;
int searchAC(struct Node *T, char str[], int val) {
DFN++;
int ans = ;
struct Node * p = T;
struct Node * root = T;
if (p == NULL) return ;
for (int i = ; str[i]; ++i) {
int id = str[i] - 'a';
p = p->pNext[id];
struct Node * temp = p;
while (temp != root && vis[temp->id] != DFN) {
vis[temp->id] = DFN;
ans += temp->flag;
temp = temp->Fail;
if (ans >= val) return false;
}
}
return true;
}
int f;
void work() {
t = ;
printf("Case #%d: ", ++f);
int n;
scanf("%d", &n);
struct Node * T = NULL;
for (int i = ; i <= n; ++i) {
scanf("%s", str[i] + );
toinsert(&T, str[i]);
}
BuildFlag(&T);
for (int i = n; i ; --i) {
if(searchAC(T, str[i], i)) {
printf("%d\n", i);
return;
}
}
printf("-1\n");
return;
} int main() {
#ifdef LOCAL
in();
#else
#endif
int t;
scanf("%d", &t);
while (t--) work();
return ;
}

Bazinga HDU - 5510 不可做的暴力的更多相关文章

  1. Bazinga HDU 5510 Bazinga(双指针)

    Bazinga HDU 5510 Bazinga(双指针) 题链 解法:对于串i来说,如果串i是不符合的,那么代表串i之前的字符串都是i的子串,那么我们求一个新的i(定义为ti),如果i是ti 的子串 ...

  2. Bazinga HDU - 5510【技巧暴力+字符串】

    题目:https://vjudge.net/problem/HDU-5510 $2015ACM/ICPC$ 亚洲区沈阳站 题目大意: 输入$t$(表示样例个数) 如何每个样例一个 $n$,表示字符串的 ...

  3. 【Bazinga HDU - 5510 】【考察strstr()的使用】【贪心】

    题意分析 1.题目大致说的是让你输出符合这种条件(在所给的字符串中至少有一个不是它的子串)的字符串对应的label,若没有输出-1: 2.判断子串可以用string.h下的strstr(s1, s2) ...

  4. hdu 5510 Bazinga(字符串kmp)

    Bazinga Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

  5. HDU 2920 分块底数优化 暴力

    其实和昨天写的那道水题是一样的,注意爆LL $1<=n,k<=1e9$,$\sum\limits_{i=1}^{n}(k \mod i) = nk - \sum\limits_{i=1}^ ...

  6. HDU 5510 Bazinga 暴力匹配加剪枝

    Bazinga Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5510 ...

  7. HDU 5510:Bazinga(暴力KMP)

    http://acm.hdu.edu.cn/showproblem.php?pid=5510 Bazinga Problem Description   Ladies and gentlemen, p ...

  8. hdu 5510 Bazinga (KMP+暴力标记)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5510 思路: 一开始直接用KMP莽了发,超时了,后面发现如果前面的字符串被后面的字符串包含,那么我们就 ...

  9. hdu 5510 Bazinga(暴力)

    Problem Description Ladies and gentlemen, please sit up straight. Don't tilt your head. I'm serious. ...

随机推荐

  1. android开发中 解决服务器端解析MySql数据时中文显示乱码的情况

    首先,还是确认自己MySql账户和密码 1.示例  账户:root   密码:123456   有三个字段   分别是_id  .username(插入有中文数据).password 1)首先我们知道 ...

  2. Linux负载均衡软件之LVS

    一. LVS简介 LVS是Linux Virtual Server的简称,也就是Linux虚拟服务器, 是一个由章文嵩博士发起的自由软件项目,它的官方站点是linuxvirtualserver.org ...

  3. js中this

    首先声明,我是小白,以下只是自己的简单理解. 先看下面的代码: (function () { console.log(this); })(); 毫无疑虑,输出的是window. 在看下面代码: (fu ...

  4. C#设计模式(11)——外观模式

    一.概念 外观模式提供了一个统一的接口,用来访问子系统中的一群接口.外观定义了一个高层接口,让子系统更容易使用.使用外观模式时,我们创建了一个统一的类,用来包装子系统中一个或多个复杂的类,客户端可以直 ...

  5. 共有11款Python 中文分词库开源软件

    件过滤: 排序: 收录时间 | 浏览数 Python 中文分词库 Yaha "哑哈"中文分词,更快或更准确,由你来定义.通过简单定制,让分词模块更适用于你的需求. "Ya ...

  6. mysql软文

    常用的MySQL复杂查询语句写法 http://www.blogjava.net/bolo/archive/2015/02/02/422649.html   mysql sql常用语句大全 http: ...

  7. fedora18下安装chrome

    ——杂言:这个fedora18是之前装着玩的,原本用的firefox来调试网站页面的,但是因为fedora上没有安装flash,以及一些其他plugin,所以还是没忍住装了chrome,一劳永逸,也好 ...

  8. Luogu 2900 [USACO08MAR]土地征用Land Acquisition

    斜率优化dp. 首先发现如果存在$x$和$y$使得$len(x) \geq len(y)$并且$wid(x) \geq wid(y)$,那么$y$直接不考虑就好了,因为在买$x$的时候就把$y$顺便带 ...

  9. window 删除文件提示指定的文件名无效或太长

    方法0: 使用 chkdsk 磁盘修复工具 .单击“开始”,点击“运行”,输入cmd并回车打开命令提示符窗口: .在此窗口输入以下命令: 例如:检查并修复D分区 chkdsk D: /f 回车,输入 ...

  10. Entity Framework Code-First(9.11):DataAnnotations - InverseProperty Attribute

    DataAnnotations - InverseProperty Attribute: We have seen in the Code-First Convention section that ...