HDU 2896 病毒侵袭

Description
         当太阳的光辉逐渐被月亮遮蔽,世界失去了光明,大地迎来最黑暗的时刻。。。。在这样的时刻,人们却异常兴奋——我们能在有生之年看到500年一遇的世界奇观,那是多么幸福的事儿啊~~
但网路上总有那么些网站,开始借着民众的好奇心,打着介绍日食的旗号,大肆传播病毒。小t不幸成为受害者之一。小t如此生气,他决定要把世界上所有带病毒的网站都找出来。当然,谁都知道这是不可能的。小t却执意要完成这不能的任务,他说:“子子孙孙无穷匮也!”(愚公后继有人了)。
万事开头难,小t收集了好多病毒的特征码,又收集了一批诡异网站的源码,他想知道这些网站中哪些是有病毒的,又是带了怎样的病毒呢?顺便还想知道他到底收集了多少带病毒的网站。这时候他却不知道何从下手了。所以想请大家帮帮忙。小t又是个急性子哦,所以解决问题越快越好哦~~

Input 第一行,一个整数N(1<=N<=500),表示病毒特征码的个数。
接下来N行,每行表示一个病毒特征码,特征码字符串长度在20—200之间。
每个病毒都有一个编号,依此为1—N。
不同编号的病毒特征码不会相同。
在这之后一行,有一个整数M(1<=M<=1000),表示网站数。
接下来M行,每行表示一个网站源码,源码字符串长度在7000—10000之间。
每个网站都有一个编号,依此为1—M。
以上字符串中字符都是ASCII码可见字符(不包括回车)。
Output         依次按如下格式输出按网站编号从小到大输出,带病毒的网站编号和包含病毒编号,每行一个含毒网站信息。 web 网站编号: 病毒编号 病毒编号 …
冒号后有一个空格,病毒编号按从小到大排列,两个病毒编号之间用一个空格隔开,如果一个网站包含病毒,病毒数不会超过3个。
最后一行输出统计信息,如下格式
total: 带病毒网站数
冒号后有一个空格。
Sample Input
3
aaa
bbb
ccc
2
aaabbbccc
bbaacc
Sample Output
web 1: 1 2 3
total: 1

首先祝一下我可爱的Neko 强生日快乐~ 永远开心~

解题思路:

因为这道题目要求要输出在母串中出现过的字串的编号, 那么就不能赤裸裸地上ac自动机的模板了, 原来的板子中end数组是记录一个字符是否是一个子串的结尾并记录以这个字符结尾的子串的个数, 那么这道题我们把end里记录为是第几个子串即子串的编号即可。 因为有多个母串, 所以我们每匹配一个母串就输出一次答案, 如果没有匹配的直接跳过, 最后输出匹配母串总数。

不知道大家做ac自动机的题都是怎么开数组大小的, 其实这道题不难, 但就因为我开小了在vjudge上面一直显示TLE???不是很懂找了好久才发现是数组开小, 很坑。

还有一个小细节要注意, 因为题目描述里写 "以上字符串中字符都是ASCII码可见字符(不包括回车)。" 所以next数组的第二维记得开大, 相应的初始化函数也要相应改大。

代码:

#include <iostream>
#include <sstream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iomanip>
#include <utility>
#include <string>
#include <cmath>
#include <vector>
#include <bitset>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <set>

using namespace std;

/*tools:
*ios::sync_with_stdio(false);
*freopen("input.txt", "r", stdin);
*/


typedef long long ll;
typedef unsigned long long ull;
const int dir[9][2] = { 0, 1, 0, -1, 1, 0, -1, 0, 1, 1, 1, -1, -1, 1, -1, -1, 0, 0 };
const ll  ll_inf = 0x7fffffff;
const int inf = 0x3f3f3f;
const int mod = (int) 1e9 + 7;
const int Max = (int) 1e5 + 51;

bool ans[505];

struct Trie {
    int next[Max][129], fail[Max], end[Max];
    int root, L;
    int Newnode() {
        // initial L equal to 1
        for (int i = 0; i < 128; ++i) {
            next[L][i] = -1;
        }
        end[L++] = -1;
        return L - 1;
    }
    void Init() {
        L = 0;
        root = Newnode();
    }
    void Insert(char *buf, int num) {
        int len = strlen(buf);
        int now = root;
        for (int i = 0; i < len; ++i) {
            if (next[now][buf[i]] == -1)
                next[now][buf[i]] = Newnode();
            now = next[now][buf[i]];
        }
        end[now] = num;
    }
    void  Build() {
        queue < int> Q;
        fail[root] = root;
        for (int i = 0; i < 128; ++i) {
            if (next[root][i] == -1) {
                next[root][i] = root;
            }
            else {
                fail[next[root][i]] = root;
                Q.push(next[root][i]);
            }
        }
        while (!Q.empty()) {
            int now = Q.front();
            Q.pop();
            for (int i = 0; i < 128; ++i) {
                if (next[now][i] == -1) {
                    next[now][i] = next[fail[now]][i];
                }
                else {
                    fail[next[now][i]] = next[fail[now]][i];
                    Q.push(next[now][i]);
                }
            }
        }
    }
    int Query(char *buf) {
        int len = strlen(buf);
        int now = root;
        int res = 0;
        memset(ans, 0, sizeof(ans));
        for (int i = 0; i < len; ++i) {
            now = next[now][buf[i]];
            int temp = now;
            while (temp != root) {
                if (end[temp] != -1) {
                    ans[end[temp]] = 1;
                    res++;
                }
                temp = fail[temp];
            }
        }
        return res;
    }
    /*
    void Debug() {
        for (int i = 0; i < L; ++i) {
            printf("id = %3d, fail = %3d, end = %3d, chi = [", i, fail[i], end[i]);
            for (int j = 0; j < 26; ++j) {
                printf("%2d", next[i][j]);
            }
            printf("]\n");
        }
    }*/
};

char ch[10100];
Trie ac;

int main() {
    //freopen("input.txt", "r", stdin);

    // definition
    int n, m;

    // initialization
    scanf("%d", &n);
    ac.Init();

    for (int i = 0; i < n; ++i) {
        scanf("%s", ch);
        // record the id
        ac.Insert(ch, i + 1);
    }
    ac.Build();

    int tot = 0;
    scanf("%d", &m);
    for (int i = 0; i < m; ++i) {
        scanf("%s", ch);

        // reserve the id
        // algorithm in Query
        if (ac.Query(ch)) {
            tot++;
            printf("web %d:", i + 1);
            for (int i = 0; i < 505; ++i) {
                if (ans[i])
                    printf(" %d", i);
            } printf("\n");
        }
    }
    printf("total: %d\n", tot);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值