Bazinga HDU - 5510 不可做的暴力

Posted stupid_one

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Bazinga HDU - 5510 不可做的暴力相关的知识,希望对你有一定的参考价值。

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 = 2000 + 2;
int tonext[502][maxn];
void get_next(char sub[], int tonext[], int lensub) {
    int i = 1, j = 0;
    tonext[1] = 0;
    while (i <= lensub) {
        if (j == 0 || 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 = 1, j = 1;
    while (i <= lenstr) {
        if (j == 0 || str[i] == sub[j]) {
            ++i, ++j;
        } else j = tonext[j];
        if (j == lensub + 1) return true;
    }
    return false;
}
char str[502][maxn];
int len[502];
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 = 1; i <= n; ++i) {
        scanf("%s", str[i] + 1);
        len[i] = strlen(str[i] + 1);
        get_next(str[i], tonext[i], len[i]);
        fa[i] = i;
    }
    printf("Case #%d: ", ++f);
    int ans = -1;
    for (int i = 2; i <= n; ++i) {
        for (int j = i - 1; j >= 1; --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 0;
}
View Code

 

有一个超时的AC自动机算法。

首先所有串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[52][2000 + 20];
struct Node {
    int flag, id;
    struct Node *Fail;
    struct Node *pNext[26];
} tree[1000000 + 20];
int t;
struct Node * create() {
    struct Node * p = &tree[t++];
    p->flag = 0;
    p->Fail = NULL;
    p->id = t - 1;
    for (int i = 0; i < 26; ++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 = 1; 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[1000000 + 20];
void BuildFlag(struct Node **T) {
    struct Node *p = *T;
    struct Node *root = *T;
    if (p == NULL) return ;
    int head = 0, tail = 0;
    que[tail++] = root;
    while (head < tail) {
        p = que[head];
        for (int i = 0; i < 26; ++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[1000000 + 20], DFN;
int searchAC(struct Node *T, char str[], int val) {
    DFN++;
    int ans = 0;
    struct Node * p = T;
    struct Node * root = T;
    if (p == NULL) return 0;
    for (int i = 1; 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 = 0;
    printf("Case #%d: ", ++f);
    int n;
    scanf("%d", &n);
    struct Node * T = NULL;
    for (int i = 1; i <= n; ++i) {
        scanf("%s", str[i] + 1);
        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 0;
}
View Code

 

以上是关于Bazinga HDU - 5510 不可做的暴力的主要内容,如果未能解决你的问题,请参考以下文章

HDU - 5510 Bazinga

HDU 5510---Bazinga(指针模拟)

HDU 5510 Bazinga(KMP)

HDU_5510_Bazinga

HDU 5510 Bazinga

hdu 5510 Bazinga (KMP+暴力标记)