Computer Virus on Planet Pandora HDOJ3695

AC自动机,要求模板串和其翻转串都是合法匹配,不用将模板串和其翻转串都加入到trie中,只要在匹配时把匹配串从正反俩个方向匹配一下就可以了,通过此题发现了以前AC自动机模板的一个错误(TLE到死),见代码吧


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>   
#include <map>
#include <string>  
#include <climits> 
#include <set>
#include <string>    
#include <sstream>
#include <utility>   
#include <ctime>

using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::getline;
using std::greater;
using std::endl;
using std::multimap;
using std::deque;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PAIR;
typedef multimap<int, int> MMAP;

const int MAXN(250010);
const int SIGMA_SIZE(26);
const int MAXM(110);
const int MAXE(300010);
const int MAXH(18);
const int INFI((INT_MAX-1) >> 1);
const int MOD(2520);
const ULL BASE(31);
const ULL LIM(1000000000000000ull);

bool vis[260];

struct AC
{
    int ch[MAXN][SIGMA_SIZE], f[MAXN];
    int val[MAXN], last[MAXN];
    int size;
    inline int idx(char temp)
    {
        return temp-'A';
    }
    void init()
    {
        memset(ch[0], 0, sizeof(ch[0]));
        val[0] = last[0] = 0;
        size = 1;
    }

    void insert(char *S, int tv)
    {
        int u = 0, id;
        for(; *S; ++S)
        {
            id = idx(*S);
            if(!ch[u][id])
            {
                memset(ch[size], 0, sizeof(ch[size]));
                val[size] = last[size] = 0;
                ch[u][id] = size++;
            }
            u = ch[u][id];
        }
        val[u] = tv;
    }

    int que[MAXN];
    int front, back;
    void construct()
    {
        int cur, u;
        front = back = 0;
        for(int i = 0; i < SIGMA_SIZE; ++i)
            if(ch[0][i])
            {
                u = ch[0][i];
                f[u] = last[u] = 0;
                que[back++] = u;
            }
        while(front < back)
        {
            cur = que[front++];
            for(int i = 0; i < SIGMA_SIZE; ++i)
            {
                u = ch[cur][i];
                if(u)
                {
                    f[u] = ch[f[cur]][i];
                    last[u] = val[f[u]]? f[u]: last[f[u]];
                    que[back++] = u;
                }
                else
                    ch[cur][i] = ch[f[cur]][i];
            }
        }
    }
    
    void find(char *T)
    {
        int u = 0, id;
        for(; *T; ++T)
        {
            id = idx(*T);
            u = ch[u][id];
            for(int pi = u; pi; )   //这里由于要求每个模板串只能加一次,所以可以把已经匹配过的模板忽略掉,否则每次都用last指针转移,TLE到死
            {						//类似如果每个节点的信息合并很好维护,就把这些具有相同后缀的节点信息合并起来,这样就不用使用last指针转移了,效率剧增					
                vis[val[pi]] = true;
                int temp = last[pi];
                last[pi] = 0;
                pi = temp;
            }
        }
    }
};

AC ac;
char str[5100010];

int main()
{
    int TC;
    scanf("%d", &TC);
    while(TC--)
    {
        int n;
        scanf("%d", &n);
        ac.init();
        for(int i = 1; i <= n; ++i)
        {
            scanf("%s", str);
            ac.insert(str, i);
        }
        ac.construct();
        while(getchar() != '\n');
        char temp;
        int qua;
        int len = 0;
        while((temp = getchar()) != '\n')
        {
            if(temp >= 'A' && temp <= 'Z')
                str[len++] = temp;
            else
            {
                scanf("%d%c", &qua, &temp);
                getchar();
                for(int i = 0; i < qua; ++i)
                    str[len++] = temp;
            }
        }
        str[len] = '\0';
        memset(vis, 0, sizeof(vis));
        ac.find(str);
        int s = 0, e = len-1;
        while(s < e)
            swap(str[s++], str[e--]);
        ac.find(str);
        int ans = 0;
        for(int i = 1; i <= n; ++i)
            if(vis[i])
                ++ans;
        printf("%d\n", ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值