XEN 3166

这题原题是spj,校oj上只用判断yes no,不过也差不多

题意分析之后就是求两个东西:

  • 字典序最小的长度为m的子序列
  • 同时这个字典序严格大于某个字符串

用序列自动机 先尽量相同,然后再考虑严格大于

#include <bits/stdc++.h>
 
using namespace std;
const int maxn = 200010;
int last[27], nxt[maxn][27], len;
 
void init(const char s[]) {
    len = (int) strlen(s);
    for (int i = 0; i < 26; ++i) last[i] = len + 1;
    for (int i = len; i >= 1; i--) {
        for (int j = 0; j < 26; ++j) {
            nxt[i][j] = last[j];
        }
        last[s[i - 1] - 'A'] = i;
    }
    for (int j = 0; j < 26; ++j) {
        nxt[0][j] = last[j];
    }
}
 
char s[2][maxn];
int n, m;
 
int solve(char pre[], char ans[], const char name[]) {
    if (len < m) return false;
    if (pre[1] == name[0]) {
        if (m <= 1) return 0;
        int a = 0, b = 0, c = 0;
        for (int i = 1, j = 1; i < m && j <= len; ++i) {
            ans[i] = pre[i];
            for (int k = pre[i + 1] - 'A' + 1; k < 26; ++k) {
                if (i + len - nxt[j][k] + 1 >= m) {
                    a = i;
                    b = j;
                    c = k;
                    break;
                }
            }
            j = nxt[j][pre[i + 1] - 'A'];
        }
        if (!a) return 0;
        ans[a + 1] = char(c + 'A');
        //
        for (int i = a + 1, j = nxt[b][c]; i < m; ++i) {
            for (int k = 0; k < 26; ++k) {
                if (i + len - nxt[j][k] + 1 >= m) {
                    ans[i + 1] = char(k + 'A');
                    j = nxt[j][k];
                    break;
                }
            }
        }
    } else {
        ans[1] = name[0];
        for (int i = 1, j = nxt[0][name[0] - 'A']; i < m; ++i) {
            for (int k = 0; k < 26; ++k) {
                if (i + len - nxt[j][k] + 1 >= m) {
                    ans[i + 1] = char(k + 'A');
                    j = nxt[j][k];
                    break;
                }
            }
        }
    }
    return 1;
}
 
string p[1010];
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        cin >> p[i];
    }
    sort(p + 1, p + 1 + n);
    bool flag = 1;
    for (int i = 1; i <= n; ++i) {
        init(p[i].c_str());
        if (!solve(s[i % 2], s[1 - i % 2], p[i].c_str())) {
            flag = 0;
            break;
        }
    }
    if (flag) cout << "YES" << '\n';
    else cout << "NO" << '\n';
 
    return 0;
}