[HEOI2015]最短不公共子串
[HEOI2015]最短不公共子串
题面
在虐各种最长公共子串、子序列的题虐的不耐烦了之后,你决定反其道而行之。
下面给出一些定义:
- 一个串的“子串”指的是它的连续的一段,例如 bcd 是 abcdef 的子串,但 bde 不是。
- 一个串的“子序列”指的是它的可以不连续的一段,例如 bde 是 abcdef 的子串,但 bdd 不是。
下面,给两个小写字母串 a, ba,b,请你计算:
- a 的一个最短的子串,它不是 b 的子串。
- a 的一个最短的子串,它不是 b 的子序列。
- a 的一个最短的子序列,它不是 b 的子串。
- a 的一个最短的子序列,它不是 b 的子序列。
题解
原本1, 用自动机match写的, 当匹配失败的时候取最小值, 然而 a = aabba, b = aabbd, 答案是2, 而不是5
所以要bfs写, 转移就完事了, 再SAM, SQAM上转移就行, 注意自动机空间是 2n
代码
struct SAM { //不管是不是多组数据都调用init
static const int N = 2e3 + 5, M = 26, C = 'a';
struct node { int fa, len, ne[M]; } tr[N << 1];
int sz, las, len, c[N], rk[N << 1], cnt[N << 1];
int sum[N << 1]; //排名为i的节点为头包含的字串数量
void init() {
rep (i, 1, sz)
tr[i].len = tr[i].fa = c[i] = 0, memset(tr[i].ne, 0, sizeof tr[i].ne);
sz = las = 1;
}
void add(int ch) {
int p = las, cur = las = ++sz;
tr[cur].len = tr[p].len + 1; ++cnt[cur];
for (; p && !tr[p].ne[ch]; p = tr[p].fa) tr[p].ne[ch] = cur;
if (p == 0) { tr[cur].fa = 1; return; }
int q = tr[p].ne[ch];
if (tr[q].len == tr[p].len + 1) { tr[cur].fa = q; return; }
int nq = ++sz; tr[nq] = tr[q]; tr[nq].len = tr[p].len + 1;
for (; p && tr[p].ne[ch] == q; p = tr[p].fa) tr[p].ne[ch] = nq;
tr[q].fa = tr[cur].fa = nq;
}
void build(char *s) {
for (int& i = len; s[i]; ++i) add(s[i] - C);
}
} sama, samb;
struct SqAM {
static const int N = 2e3 + 5, M = 26, C = 'a';
struct Node { int fa, ne[26]; } tr[N << 1];
int rt, tot, lst[M];
int newNode() { return ++tot, memset(tr[tot].ne, 0, sizeof tr[0].ne), tot; }
void init() { tot = 0; rep (i, 0, M - 1) lst[i] = 1; rt = newNode(); }
void insert(int ch) {
int p = lst[ch], cur = newNode(); tr[cur].fa = p;
rep (i, 0, M - 1) for (int j = lst[i]; j && !tr[j].ne[ch]; j = tr[j].fa)
tr[j].ne[ch] = cur;
lst[ch] = cur;
}
void build(char* s) { for (int i = 0; s[i]; insert(s[i++] - C)); }
} A, B;
const int N = 2e3 + 5;
int st[N << 1][N << 1];
char a[N], b[N];
int bfs1() {
queue<pair<PII, int>> q; q.push({ { 1, 1, }, 0 }); st[1][1] = 1;
while (!q.empty()) {
auto cur = q.front(); q.pop();
int x = cur.fi.fi, y = cur.fi.se, t = cur.se;
rep (i, 0, 25) {
int nx = sama.tr[x].ne[i], ny = samb.tr[y].ne[i];
if (nx && ny) if (st[nx][ny] != 1) st[nx][ny] = 1, q.push({ { nx, ny }, t + 1 });
if (nx && !ny) return t + 1;
}
}
return -1;
}
int bfs2() {
queue<pair<PII, int>> q; q.push({ { 1, 1, }, 0 }); st[1][1] = 1;
while (!q.empty()) {
auto cur = q.front(); q.pop();
int x = cur.fi.fi, y = cur.fi.se, t = cur.se;
rep (i, 0, 25) {
int nx = sama.tr[x].ne[i], ny = B.tr[y].ne[i];
if (nx && ny) if (st[nx][ny] != 1) st[nx][ny] = 1, q.push({ { nx, ny }, t + 1 });
if (nx && !ny) return t + 1;
}
}
return -1;
}
int bfs3() {
queue<pair<PII, int>> q; q.push({ { 1, 1, }, 0 }); st[1][1] = 3;
while (!q.empty()) {
auto cur = q.front(); q.pop();
int x = cur.fi.fi, y = cur.fi.se, t = cur.se;
rep (i, 0, 25) {
int nx = A.tr[x].ne[i], ny = samb.tr[y].ne[i];
if (nx && ny) if (st[nx][ny] != 3) st[nx][ny] = 3, q.push({ { nx, ny }, t + 1 });
if (nx && !ny) return t + 1;
}
}
return -1;
}
int bfs4() {
queue<pair<PII, int>> q; q.push({ { 1, 1, }, 0 }); st[1][1] = 4;
while (!q.empty()) {
auto cur = q.front(); q.pop();
int x = cur.fi.fi, y = cur.fi.se, t = cur.se;
rep (i, 0, 25) {
int nx = A.tr[x].ne[i], ny = B.tr[y].ne[i];
if (nx && ny) if (st[nx][ny] != 4) st[nx][ny] = 4, q.push({ { nx, ny }, t + 1 });
if (nx && !ny) return t + 1;
}
}
return -1;
}
int main() {
cin >> a >> b; samb.init(); samb.build(b); B.init(); B.build(b);
sama.init(); sama.build(a); A.init(); A.build(a);
cout << bfs1() << '\n' << bfs2() << '\n' << bfs3() << '\n' << bfs4();
return 0;
}