NOIAC1755 Trie

NOIAC1755 Trie

题目大意

给定一个字典(字符串的集合), 有若干次询问, 每次询问给出一个文本串 \(S\), 需要回答 \(S\) 是否有某个子串与字典内的某个单词(字符串)同构.
一个串 \(S\) 与一个串 \(T\) 同构, 首先需要 \(|S|=|T|\), 并且存在一个关于字符集的双射 \(f\) 使得 \(S_i = f(T_i)\).
比如 \(ABB\)\(XYY, BAA, TSS\) 同构, 但不和 \(AAB, XXY, ZZZ\) 同构.

数据范围

\(N \le 10^5, M \le 5 \times 10^5\)

解题思路

首先有个暴力的思路,即枚举每个子串,然后分配为字典序最小的串,哈希匹配一下即可。

容易发现复杂度瓶颈在枚举子串而且不好优化。因此我们考虑如何用 AC 自动机来完成匹配的过程。

我们可以记录每个字符当前位置和上一个出现位置的差,如果两个字符串的这个数组相同,即可认定两个字符串同构。因为字符集比较大,因此我们用 map 存暴力跳 fail 即可。另外要注意匹配时如果长度比上一个位置的差还要短,那么我们自动把它变为 i 即可,也就是匹配前缀是我们把 i 和 更大的数看成一个即可。

代码

/*
     />  フ
     |  _  _|
     /`ミ _x 彡
     /      |
    /   ヽ   ?
 / ̄|   | | |
 | ( ̄ヽ__ヽ_)_)
 \二つ
 */

#include <queue>
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MP make_pair
#define ll long long
#define fi first
#define se second
using namespace std;

template <typename T>
void read(T &x) {
    x = 0; bool f = 0;
    char c = getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
    for (;isdigit(c);c=getchar()) x=x*10+(c^48);
    if (f) x=-x;
}

template<typename F>
inline void write(F x, char ed = '\n') {
	static short st[30];short tp=0;
	if(x<0) putchar('-'),x=-x;
	do st[++tp]=x%10,x/=10; while(x);
	while(tp) putchar('0'|st[tp--]);
	putchar(ed);
}

template <typename T>
inline void Mx(T &x, T y) { x < y && (x = y); }

template <typename T>
inline void Mn(T &x, T y) { x > y && (x = y); }

#include <map>
const int N = 1005000;
#define init(p, c) (mp[(p)].find(c) != mp[(p)].end())
char s[N]; map<int, int> mp[N]; int ed[N], dep[N], cnt;
int las[30], d[N];
void work(int len) {
	memset(las, 0, sizeof(las));
	for (int i = 1;i <= len; i++)
		d[i] = i - las[s[i]-'A'], las[s[i]-'A'] = i;
}

void insert(int len) {
	int p = 0;
	for (int i = 1;i <= len; i++) {
		int c = d[i];
		if (!init(p, c)) mp[p][c] = ++cnt;
		p = mp[p][c], dep[p] = i;
	}
	ed[p] = 1;
}

int f[N];
void build(void) {
	queue<int> q;
	for (auto v: mp[0]) q.push(v.se);
	while (q.size()) {
		int x = q.front(); q.pop();
		ed[x] |= ed[f[x]];
		for (auto v: mp[x]) {
			q.push(v.se); int fat;
			for (fat = f[x]; fat && !init(fat, min(v.fi, dep[fat] + 1)); fat = f[fat]);
			if (init(fat, min(v.fi, dep[fat] + 1))) f[v.se] = mp[fat][min(v.fi, dep[fat] + 1)];
		}
	}
}

bool check(int len) {
	int p = 0;
	for (int i = 1;i <= len; i++) {
		for (; p && !init(p, min(dep[p] + 1, d[i])); p = f[p]);
		if (init(p, min(dep[p] + 1, d[i]))) p = mp[p][min(dep[p] + 1, d[i])];
		if (ed[p]) return 1;
	}
	return 0;
}

int m, n;
int main() {
	read(n);
	for (int i = 1;i <= n; i++) {
		scanf ("%s", s + 1);
		int len = strlen(s + 1); 
		work(len), insert(len);
	}
	build(), read(m);
	for (int i = 1;i <= m; i++) {
		scanf ("%s", s + 1);
		int len = strlen(s + 1);
		work(len), puts(check(len) ? "Yes" : "No");
	}
	return 0;
}
posted @ 2020-08-28 17:25  Hs-black  阅读(131)  评论(0编辑  收藏  举报