AtCoder ABC 161
April 18, 2020
https://atcoder.jp/contests/abc161
ABC161に参加したのでメモ。
| A | B | C | D | E | F | 
|---|---|---|---|---|---|
| o | o | o | o | x | x | 
A~Dは問題なく解けた。
D - Lunlun Number
桁DP + 二分探索で解いた。ある正の整数に対して、以下のルンルン数を数えることができれば、二分探索でK番目のルンルン数を見つけることができる。 桁DPでは、ある桁の数がleading zeroなのかどうかに注意して遷移を考える。
桁DPについては、似たような問題として、
がある。
こういう問題は桁DPを使えば脳死で解けるが、そうして解いても学びが得られない。あとで解説にあるようにBFSで解くなどしたい。
#define MAX_DIGIT 30
i64 dp[MAX_DIGIT + 1][2][2][10];
// [決定した桁数][未満フラグ][leading zeros][その桁の数字]
i64 count_lum(i64 n) {
    string ns = to_string(n);
    i64 L = ns.length();
    REP(i, L + 1) REP(j, 2) REP(k, 2) REP(d, 10) dp[i][j][k][d] = 0;
    dp[0][0][1][0] = 1;
    REP(i, L) {
        i64 D = ns[i] - '0';
        REP(smaller, 2) {
            REP(zeros, 2) {
                REP(d_prev, 10) {
                    for (i64 d = 0; d <= (smaller ? 9 : D); d++) {
                        if (zeros) {
                            dp[i + 1][smaller || d < D][d == 0][d]
                                 += dp[i][smaller][zeros][d_prev];
                        } else if (abs(d - d_prev) <= 1) {
                            dp[i + 1][smaller || d < D][0][d
                                 += dp[i][smaller][zeros][d_prev];
                        }
                    }
                }
            }
        }
    }
    i64 res = 0;
    REP(i, 10) res += dp[L][0][0][i] + dp[L][1][0][i];
    return res;
}
#define INF 1152921504606846976
int main() {
    i64 K; cin >> K;
    // x以下のるんるん数を数える
    i64 lb = 0, ub = INF;
    while (ub - lb > 1) {
        i64 mid = (lb + ub) / 2;
        if (count_lum(mid) >= K) {
            ub = mid;
        } else {
            lb = mid;
        }
    }
    cout << ub << endl;
    return 0;
}