HDU 6096 String AC自动机(多种解法)

传送门:HDU6096

题意:给出n个字符串和q个询问,每次询问给出两个串 p 和 s 。要求统计所有字符串中前缀为 p 且后缀为 s (不可重叠)的字符串的数量。

思路:从dalao哪里学来的巧妙的解法:

首先是要离线处理。

将询问做成s + ‘#’ + p的模式串插入到AC自动机里,并记录插入的结点位置,然后将每一个原串str做成str + ‘#’ + str的主串,用AC自动机进行匹配,每匹配到一个就将对应结点的计数器++,最后对于每个询问输出其插入的结点位置的计数器就行了。

加‘#’的目的是保证匹配的是对应的后缀和前缀。

为了避免aa aa询问到aaa的情况,我们对AC自动机中的每一个结点记录一个长度LEN[i],匹配的时候只有长度大于等于LEN[i]的串才能算匹配成功。


真的是很巧妙的思路。

代码:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int> P;
const int MAXN = 2000010;
int pos[MAXN];
struct Trie{  
    int next[MAXN][27], fail[MAXN], LEN[MAXN], ans[MAXN];
    int root, L;  
    int insert(char buf[])  
    {  
        int len = strlen(buf), now = 0;  
        for(int i = 0; i < len; i++)  
        {  
            if(next[now][buf[i] - 'a'] == 0)
			{
				next[now][buf[i] - 'a'] = ++L;
				LEN[L] = i + 1;
			} 
            now = next[now][buf[i] - 'a'];
        }
        return now;
    }  
    void init()//不要忘记初始化  
    {  
        memset(next, 0, sizeof(int) * (L + 1) * 27);
        memset(fail, 0, sizeof(int) * (L + 1));
        memset(LEN, 0, sizeof(int) * (L + 1));
        memset(ans, 0, sizeof(int) * (L + 1));
		root = L = 0;
    }  
    void build()  
    {  
        queue<int>q;
        fail[root] = root;
        for(int i = 0; i < 27; i++)  
        if(next[root][i] == 0)
        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 < 27; i++)
            if(next[now][i] == 0)
            next[now][i] = next[fail[now]][i];  
            else  
            {  
                fail[next[now][i]] = next[fail[now]][i];
                q.push(next[now][i]);  
            }  
        }  
    }  
    void query(char buf[], int len)  
    {  
       int now = root;
        for(int i = 0; buf[i]; i++)  
        {  
            now = next[now][buf[i] - 'a'];  
            int tmp = now;  
            while(tmp != root)  
            {  
                if(LEN[tmp] &l
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值