HDU - 6096 (2020.3.22训练F题)

Problem
Bob has a dictionary with N words in it.
Now there is a list of words in which the middle part of the word has continuous letters disappeared. The middle part does not include the first and last character.
We only know the prefix and suffix of each word, and the number of characters missing is uncertain, it could be 0. But the prefix and suffix of each word can not overlap.
For each word in the list, Bob wants to determine which word is in the dictionary by prefix and suffix.
There are probably many answers. You just have to figure out how many words may be the answer.
Input
The first line of the input gives the number of test cases T; T test cases follow.
Each test case contains two integer N and Q, The number of words in the dictionary, and the number of words in the list.
Next N line, each line has a string Wi, represents the ith word in the dictionary (0<|Wi|≤100000)
Next Q line, each line has two string Pi , Si, represents the prefix and suffix of the ith word in the list (0<|Pi|,|Si|≤100000,0<|Pi|+|Si|≤100000)
All of the above characters are lowercase letters.
The dictionary does not contain the same words.

Limits
T≤5
0<N,Q≤100000
∑Si+Pi≤500000
∑Wi≤500000
Output
For each test case, output Q lines, an integer per line, represents the answer to each word in the list.

看了别人写的题解后,原来可以有很巧妙地方法拼凑出AC自动机解法
把w字符串拼凑成w+{+w的形式(因为{ascii值比z大一,方便构造字典树),这样它的后缀和前缀相接
要寻找的前缀p和后缀s也拼凑成s+p的形式插入trie树中
然后就进行寻找操作了,每个被寻找的前后缀字符串保存更新好匹配数就ok了

AC代码

#include<iostream>
#include<string>
#include<queue>
#include<string.h>
using namespace std;
typedef long long ll;
const ll maxn = 500005;

ll T, n, q;
ll cnt;
string w[maxn], p, s;
ll trie[maxn][27];
ll cntword[maxn];
ll fail[maxn];
ll length[maxn];
ll ans[maxn];
ll pos[maxn];

ll insert(string str)
{
	ll len = str.size();
	ll pos = 0;
	for (ll i = 0; i < len; i++)
	{
		ll next = str[i] - 'a';
		if (!trie[pos][next])
		{
			trie[pos][next] = ++cnt;
			length[cnt] = i + 1;
		}
		pos = trie[pos][next];
	}
	cntword[pos] = 1;     
	return pos;
}
void getfail()
{
	queue<ll> Q;
	for (ll i = 0; i <= 26; i++)
		if (trie[0][i])
		{
			fail[trie[0][i]] = 0;
			Q.push(trie[0][i]);
		}
	ll now;
	while (!Q.empty())
	{
		now = Q.front(); 
		Q.pop();
		for (ll i = 0; i <= 26; i++)
		{
			if (trie[now][i])
			{
				fail[trie[now][i]] = trie[fail[now]][i];
				//cout<<"*"<<fail[trie[now][i]]<<endl;
				Q.push(trie[now][i]);
			}
			else
				trie[now][i] = trie[fail[now]][i];
		}
	}
}
void query(string str)
{
	ll len = str.size();
	ll now = 0;
	for (ll i = 0; i < len; i++)
	{
		now = trie[now][str[i] - 'a'];
		//cout<<"now="<<now<<endl;
		for (ll j = now; j; j = fail[j])
		{
			//cout<<"*="<<str[i]<<endl;
			//cout<<"length="<<length[j]<<endl;
			if (cntword[j] && length[j] <= ((len - 1) / 2 + 1))
			{
				ans[j] += cntword[j];
			}
			//if(length[j]<=((len-1)/2+1))        
			//{
			//	ans[j]++;
			//}
		}
	}
}		
int main()
{
	scanf("%d", &T);
	while (T--)
	{
		memset(trie, 0, sizeof(trie));
		memset(cntword, 0, sizeof(cntword));
		memset(fail, 0, sizeof(fail));
		memset(length, 0, sizeof(length));
		memset(ans, 0, sizeof(ans));
		cnt = 0;

		scanf("%d%d", &n, &q);
		for (ll i = 0; i < n; i++)
		{
			cin >> w[i];
			string temp = "{";  
			w[i] += temp + w[i];
		}
		for (ll i = 0; i < q; i++)
		{
			cin >> p >> s;
			string temp = "{";
			s += temp + p;
			pos[i] = insert(s);
		}
		getfail();
		for (ll i = 0; i < n; i++)
			query(w[i]);
		for (ll i = 0; i < q; i++)
			printf("%d\n", ans[pos[i]]);
	}
	return 0;
}

发布了16 篇原创文章 · 获赞 21 · 访问量 1321

猜你喜欢

转载自blog.csdn.net/rainbowower/article/details/105118090