题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5507
题目大意: 给你n个串, q次询问(x, y), x是否为y的子序列, x是否为y的子串。( n,q,总长度≤105 )
思路:这题数据好像很水, 整个差不多就是在打暴力, 时间复杂度什么的都不知道扔到哪去了。
关于x是否为y的子序列。 预处理f[i][j]表示从i往后第一个字符为’a’+j的位置。 每次询问用f数组让x在y上跳, 跳出去了为0。
关于x是否为y的子串。 先将n个串建立一个ac自动机。 对于所有询问的y串, 在ac自动机上跑, 记录y所能到的所有有结束标记的节点, 算上fail链。 可以用map存起来。 每次询问O(logn)直接回答。
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define pi pair<int, int >
#define mk(i, j) make_pair(i, j)
using namespace std;
const int N = (int)1e5 + 10;
int n, q, E[N][2], ask[N], tim;
char str[N]; int st[N], ed[N], f[N][26];
map<pi, bool > M;
struct ACM{
int cnt, rt, ch[N][26], fail[N], lst[N], edd[N], pre[N], fa[N];
void init(){
cnt = 0; memset(ch[0], 0, sizeof(ch[0]));
}
int NewNode(){
cnt ++; fail[cnt] = fa[cnt] = pre[cnt] = lst[cnt] = 0;
memset(ch[cnt], 0, sizeof(ch[cnt]));
return cnt;
}
void insert(int id){
int p = rt;
for (int i = st[id]; i <= ed[id]; i ++){
int j = str[i] - 'a';
if (!ch[p][j]) ch[p][j] = NewNode(), pre[cnt] = j, fa[cnt] = p;
p = ch[p][j];
}
edd[id] = p; lst[p] = 1;
}
int head, tail, que[N];
void call_fail(){
head = tail = 0;
que[tail = 1] = rt;
while (head < tail){
int u = que[++ head];
for (int j = 0; j < 26; j ++)
if (ch[u][j]) que[++ tail] = ch[u][j];
int p = fa[u];
while (u != rt && p != rt && !ch[fail[p]][pre[u]]) p = fail[p];
if (p == rt) continue;
fail[u] = ch[fail[p]][pre[u]];
}
}
void find(int id){
int u = rt;
for (int i = st[id]; i <= ed[id]; i ++){
int j = str[i] - 'a'; u = ch[u][j];
for (int p = u; p; p = fail[p]){
if (lst[p]){
M[mk(p, id)] = 1;
}
if (!lst[fail[p]]) fail[p] = fail[fail[p]];
}
}
}
}acm;
int subsequence(int x, int y){
int p = st[y];
for (int i = st[x]; i <= ed[x]; i ++){
p = f[p][str[i] - 'a'];
if (p > ed[y]) return 0;
p ++;
}
return 1;
}
int substring(int x, int y){
return M[mk(acm.edd[x], y)];
}
int main(){
int T; scanf("%d", &T);
while (T --){
scanf("%d %d", &n, &q);
for (int i = 1; i <= n; i ++){
st[i] = ed[i - 1] + 1;
scanf("%s", str + st[i]);
ed[i] = strlen(str + st[i]) + ed[i - 1];
}
for (int i = 0; i < 26; i ++) f[ed[n] + 1][i] = ed[n] + 1;
for (int i = ed[n]; i >= 1; i --)
for (int j = 0; j < 26; j ++)
if (str[i] == 'a' + j) f[i][j] = i;
else f[i][j] = f[i + 1][j];
acm.init(); M.clear();
for (int i = 1; i <= n; i ++) acm.insert(i);
acm.call_fail();
tim ++;
for (int i = 1; i <= q; i ++){
scanf("%d %d", E[i] + 0, E[i] + 1);
ask[E[i][1]] = tim;
}
for (int i = 1; i <= n; i ++) if (ask[i] == tim) acm.find(i);
for (int i = 1; i <= q; i ++) printf("%d%d", subsequence(E[i][0], E[i][1]), substring(E[i][0], E[i][1]));
puts("");
}
return 0;
}