はまやんはまやんはまやん

hamayanhamayan's blog

Three Letters [CODE FESTIVAL 2018 Final D]

https://beta.atcoder.jp/contests/code-festival-2018-final-open/tasks/code_festival_2018_final_d

解説

https://beta.atcoder.jp/contests/code-festival-2018-final-open/submissions/3622829

O(90000*52*52)を目指す。
まず、encode関数を用意して、全ての文字を大小関係を保ちながら0~51にしておこう。
i,jを全探索する。
このi,jについてkを数えていく。
n番目の文字列について、i,jの位置は先頭から順番に決める。
すると、j以降の要素は全てkになることができる。
この文字についてvisを更新しておき、最後にcntで数え上げる。
注意することがあるが、visを文字列毎に初期化して使うことになるが、注意しないとO(30000*52^3)になってしまいTLEする。
O(90000*52*52)を守ろう。
あとは、(-満たす文字列の組み合わせ,i,j,k)のtupleを作り、最小となるものが答え。

int N; string A[30101]; int M[301010];
using T = tuple<int, int, int, int>;
//---------------------------------------------------------------------------------------------------
int encode(char c) {
    if ('A' <= c and c <= 'Z') return c - 'A';
    return c - 'a' + 26;
}
char decode(int i) {
    if (i < 26) return char('A' + i);
    return char('a' + i - 26);
}
//---------------------------------------------------------------------------------------------------
int cnt[52], vis[52];
void _main() {
    cin >> N;
    rep(i, 0, N) {
        cin >> A[i];
        M[i] = A[i].length();
        fore(c, A[i]) c = encode(c);
    }
 
    T ans = make_tuple(inf, inf, inf, inf);
    rep(i, 0, 52) rep(j, 0, 52) {
        rep(n, 0, N) {
            int idx = 0;
            while (idx < M[n] and A[n][idx] != i) idx++;
            idx++;
            while (idx < M[n] and A[n][idx] != j) idx++;
            idx++;
            rep(m, idx, M[n]) vis[A[n][m]] = 1;
 
            rep(m, idx, M[n]) if (vis[A[n][m]]) {
                cnt[A[n][m]]++;
                vis[A[n][m]] = 0;
            }
        }
        rep(k, 0, 52) if(cnt[k]) {
            chmin(ans, make_tuple(-cnt[k], i, j, k));
            cnt[k] = 0;
        }
    }
 
    int ma, i, j, k;
    tie(ma, i, j, k) = ans;
    printf("%c%c%c\n", decode(i), decode(j), decode(k));
}