[HEOI2015]最短不公共子串

[HEOI2015]最短不公共子串

题面

在虐各种最长公共子串、子序列的题虐的不耐烦了之后,你决定反其道而行之。

下面给出一些定义:

  • 一个串的“子串”指的是它的连续的一段,例如 bcd 是 abcdef 的子串,但 bde 不是。
  • 一个串的“子序列”指的是它的可以不连续的一段,例如 bde 是 abcdef 的子串,但 bdd 不是。

下面,给两个小写字母串 a, ba,b,请你计算:

  1. a 的一个最短的子串,它不是 b 的子串。
  2. a 的一个最短的子串,它不是 b 的子序列。
  3. a 的一个最短的子序列,它不是 b 的子串。
  4. 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;
}
posted @ 2020-12-16 00:53  洛绫璃  阅读(71)  评论(0编辑  收藏  举报