String

思路

我们把每一个后缀+前缀以后缀+任意不是a~z的字符+前缀建立AC自动机,再把字典中的字符串也以一样的形式跑一边AC自动机,求最后每一个后缀加前缀对应的节点出现的次数就可以了

代码(借鉴

#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] <=  len) ans[tmp]++;
                tmp = fail[tmp];
            }  
        }  
    }  
}AC;
char str[MAXN];
char *s[100010];
int len[100010];
char s1[100010], s2[100010];
int main()
{
	int T, n, q;
	scanf("%d", &T);
	while(T--)
	{
		AC.init();
		scanf("%d %d", &n, &q);
		int cnt = 0;
		for(int i = 0; i < n; i++)
		{
			s[i] = str + cnt;
			scanf("%s", s[i]);
			len[i] = strlen(s[i]) + 1;
			cnt += len[i];
			strcpy(str + cnt, s[i]);
			str[cnt - 1] = 'z' + 1;
			cnt += len[i];
		}
		for(int i = 0; i < q; i++)
		{
			s1[0] = 'z' + 1;
			scanf("%s%s", s1 + 1, s2);
			strcat(s2, s1);
			pos[i] = AC.insert(s2);
		}
		AC.build();
		for(int i = 0; i < n; i++)
		AC.query(s[i], len[i]);
		for(int i = 0; i < q; i++)
		printf("%d\n", AC.ans[pos[i]]);
	}
 	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值