HDU 4787 GRE Words Revenge 在线AC自动机

本文介绍了一种使用AC自动机构造双机方案解决特定编程竞赛问题的方法。该方案在节点数量达到一定上限时,将辅助自动机的所有信息合并到主自动机中,以避免超出限制。文中提供了一个完整的C++实现示例,并通过具体实例展示了如何处理字符串匹配及计数等问题。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4787

构造两个自动机 当一个自动机大于节点上限,就将BUFF全部加入AC
有个问题就是TOP在1000的时候能AC 5000和500就会WA不是很懂为什么

代码:

#include <bits/stdc++.h>
#define sf scanf
#define pf printf
using namespace std;
const int maxn = 100000 + 10;
struct AcTrie{
    int ch[maxn][2],tot,v[maxn],fail[maxn];
    void Init(){
        memset( ch[0] , 0 ,sizeof ch[0]);
        v[0] = 0;
        tot = 1;
    }
    int NewNode(){
        memset( ch[tot] , 0, sizeof ch[0] );
        v[tot] = 0;
        return tot++;
    }
    void Insert(char * s){
        int cur = 0;
        while(*s){
            int idx = *s - '0';
            if(!ch[cur][idx]){
                ch[cur][idx] = NewNode();
            }
            cur = ch[cur][idx];
            s++;
        }
        v[cur] = 1;
    }
    void GetFail(){
        queue<int> Q;Q.push(0);
        fail[0] = -1;
        while(!Q.empty()){
            int cur = Q.front();Q.pop();
            for(int idx = 0;idx < 2;++idx){
                if(ch[cur][idx]){
                    int f = fail[cur];
                    while(~f && !ch[f][idx]) f = fail[f];
                    fail[ch[cur][idx]] = (f == -1) ? 0 : ch[f][idx];
                    Q.push(ch[cur][idx]);
                }
            }
        }
    }

    int Search(char *s){
        int cur = 0,ret = 0,f;
        while(*s){
            int idx = *s - '0';
            if(!ch[cur][idx]){
                f = fail[cur];
                while(f != -1 && !ch[f][idx]) f = fail[f];
                cur = (f == -1) ? 0 : ch[f][idx];
            }else cur = ch[cur][idx];
            f = cur;
            while(f){
                ret += v[f];
                f = fail[f];
            }
            s++;
        }
        return ret;
    }
}ac,buff;
const int maxnn = 5000000 + 50,TOP = 999;
char str[maxnn],tmp[maxnn];

void DFS(int rt1,int rt2){
    ac.v[rt1] = ac.v[rt1] | buff.v[rt2];
    for(int i = 0;i < 2;++i){
        if(ac.ch[rt1][i] && buff.ch[rt2][i]) DFS(ac.ch[rt1][i],buff.ch[rt2][i]);
        else if(!ac.ch[rt1][i] && buff.ch[rt2][i]) DFS(ac.ch[rt1][i] = ac.NewNode(),buff.ch[rt2][i]);
    }
}
void getRev(int k){
    int len = strlen(str + 1);
    char* tmp_s = str + 1,*tmp_tmp = tmp + 1;
    tmp_tmp[len] = 0;
    for(int i = 0;i < len;++i) tmp_tmp[i] = tmp_s[ (i + k) % len ];
}
int main(){
    int T,ca = 0;sf("%d",&T);
    tmp[0] = '#';
    while( T-- ){
        int n,pre = 0;sf("%d",&n);
        ac.Init();
        buff.Init();
        ac.GetFail();
        buff.GetFail();
        pf("Case #%d:\n",++ca);
        for(int i = 0;i < n;++i){
            sf("%s",str);
            getRev(pre);
            if(str[0] == '+') buff.Insert(tmp + 1);
            else{
                if(buff.tot > TOP){
                    DFS(0,0);
                    ac.GetFail();
                    buff.Init();
                    buff.GetFail();
                }
                else buff.GetFail();
                pf("%d\n",pre = (buff.Search(tmp + 1) + ac.Search(tmp + 1)));
            }
        }
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值