HDU 2896/3065 病毒侵袭(AC自动机)

题意:第一行,一个整数N(1<=N<=500),表示病毒特征码的个数。接下来N行,每行表示一个病毒特征码,特征码字符串长度在20—200之间。每个病毒都有一个编号,依此为1—N。不同编号的病毒特征码不会相同。在这之后一行,有一个整数M(1<=M<=1000),表示网站数。接下来M行,每行表示一个网站源码,源码字符串长度在7000—10000之间。每个网站都有一个编号,依此为1—M。以上字符串中字符都是ASCII码可见字符(不包括回车)。

输出:依次按如下格式输出按网站编号从小到大输出,带病毒的网站编号和包含病毒编号,每行一个含毒网站信息。

web 网站编号: 病毒编号 病毒编号 …冒号后有一个空格,病毒编号按从小到大排列,两个病毒编号之间用一个空格隔开,如果一个网站包含病毒,病毒数不会超过3个。最后一行输出统计信息,如下格式:total: 带病毒网站数。冒号后有一个空格。

思路:AC自动机模板题。只是需要注意有多个母串,所以用母串扫的时候一次找到不能将num数组置零,需要用其他办法。我用了一个flag数组记录。

特别注意的是:如果对整个trie用memset刷新初始值会MLE,如果使用过程中逐个初始化才能AC。

3065的题意类似,需要输出每个模式串出现的次数,查询的时候使用一个数组进行记录就可以了。这题又给了我一个教训,HDU的题目都是多组数据的,虽然题目里并没有说明。

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define INF 0x3fffffff
#define N 100005
#define M 128
int t[N][M],fail[N],num[N],output[3],sum,flag[505];
char s[10005];
int n,m,top;
queue q;
int newnode(){//必须这样初始化才能AC
    top++;
    for(int i = 0;i


3065:

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define INF 0x3fffffff
#define N 50005
int t[N][27],fail[N],num[N],res[1005];
int n,top;
char s[1005][55],b[2000005];
queue q;
int newnode(){
    top++;
    for(int i = 0;i<27;i++)
        t[top][i] = -1;
    return top;
}
void init(){
    memset(fail, 0, sizeof(fail));
    memset(num, 0,sizeof(num));
    memset(res, 0, sizeof(res));
    for(int i = 0;i<27;i++)
        t[0][i] = 1;
    top = 0;
    newnode();
}
void insert(char* s,int id){
    int i,r = 1;
    for(i = 0;s[i];i++){
        if(t[r][s[i]-'A'] == -1)
            t[r][s[i]-'A'] = newnode();
        r = t[r][s[i]-'A'];
    }
    num[r] = id;
}
void buildDFA(){
    int i,now;
    q.push(1);
    while(!q.empty()){
        now = q.front();
        q.pop();
        for(i = 0;i<27;i++){
            if(t[now][i] == -1)
                t[now][i] = t[fail[now]][i];
            else{
                fail[t[now][i]] = t[fail[now]][i];
                q.push(t[now][i]);
            }
        }
    }
}
void search(char* s){
    int i,r = 1,tmp;
    for(i = 0;s[i];i++){
        if(!(s[i]>='A'&&s[i]<='Z'))
            s[i] = 'Z'+1;
        r = tmp = t[r][s[i]-'A'];
        while(tmp){
            if(num[tmp])
                res[num[tmp]]++;
            tmp = fail[tmp];
        }
    }
}
int main(){
    int i;
    while(scanf("%d",&n)!=EOF){
        init();
        for(i = 1;i<=n;i++){
            scanf("%s",s[i]);
            insert(s[i],i);
        }
        buildDFA();
        scanf("%s",b);
        search(b);
        for(i = 1;i<=n;i++)
            if(res[i])
                printf("%s: %d\n",s[i],res[i]);
    }
    return 0;
}


你可能感兴趣的:(字符串)