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;
}

有一个超时的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;
}

时间: 2024-10-13 21:07:50

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

hdu 5510 Bazinga(字符串kmp)

Bazinga Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2287    Accepted Submission(s): 713 Problem Description Ladies and gentlemen, please sit up straight.Don't tilt your head. I'm serious.For

hdu 4932 Miaomiao&#39;s Geometry 暴力枚举

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4932 Miaomiao's Geometry Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 694    Accepted Submission(s): 180 Problem Description There are N point

HDU 4930 Fighting the Landlords(暴力枚举+模拟)

HDU 4930 Fighting the Landlords 题目链接 题意:就是题中那几种牌型,如果先手能一步走完,或者一步让后手无法管上,就赢 思路:先枚举出两个人所有可能的牌型的最大值,然后再去判断即可 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct Player { int rank[15]; } p1, p2; int t, h

hdu 1399 Starship Hakodate-maru (暴力搜索)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1399 题目大意:找到满足i*i*i+j*(j+1)*(j+2)/6形式且小于等于n的最大值. 1 #include<iostream> 2 #include<cstdio> 3 4 using namespace std; 5 6 int main() 7 { 8 int n; 9 while(scanf("%d",&n),n) 10 { 11 int j,

HDU 5280 Senior&#39;s Array (暴力,水)

题意:给一个数列,再给一个数字p,要求p一定要替换掉数列中的一个元素,然后求最大连续子序列之和. 思路:1000*1000的复杂度,O(n*n) .就是每个都试,然后求和. 1 #include <bits/stdc++.h> 2 #define LL long long 3 #define pii pair<int,int> 4 #define INF 0x7f7f7f7f 5 using namespace std; 6 const int N=2000; 7 int a[N]

hdu 4932 Miaomiao&#39;s Geometry(暴力)

题目链接:hdu 4932 Miaomiao's Geometry 题目大意:在x坐标上又若干个点,现在要用若干条相等长度的线段覆盖这些点,若一个点被一条线段覆盖,则必须在这条线的左端点或者是右端点,并且各个线段放的位置不能又重叠,求最大长度. 解题思路:这题有坑点,比赛的时候o(n)的算法去寻找两点之间最短距离.但起始这样是不行的,比如-1 0 10 12 18 20,这样维护过去的话,最短应该是12~18,长度为6,这段线段可以覆盖12和18的点,然后-1和20又在两端.于是只有0和10两点

hdu 4876 ZCC loves cards(暴力)

题目链接:hdu 4876 ZCC loves cards 题目大意:给出n,k,l,表示有n张牌,每张牌有值.选取其中k张排列成圈,然后在该圈上进行游戏,每次选取m(1≤m≤k)张连续的牌,取牌上值的亦或和.要求找到一个圈,使得L~R之间的数都可以得到,输出R.如果R < L输出0. 解题思路:暴力,首先预处理出来每种选取的亦或值,然后在该基础上从可以组成L的状态中挑选一个,L+1的状态中挑取一个,知道说总的挑取出所有状态中选中的牌的个数大于K为值,然后用全排序去查找最大的R. #includ

hdu 1015 Safecracker (纯暴力)

Safecracker Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 8183    Accepted Submission(s): 4143 Problem Description === Op tech briefing, 2002/11/02 06:42 CST === "The item is locked in a Klein

hdu 5510 Bazinga (KMP+暴力标记)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5510 思路: 一开始直接用KMP莽了发,超时了,后面发现如果前面的字符串被后面的字符串包含,那么我们就不需要用前面的字符串去比较了,把他标记掉就好了. 实现代码: #include<iostream> #include<algorithm> #include<cstring> #include<cstdio> using namespace std; char