naoya_t@hatenablog

いわゆるチラシノウラであります

ABC 114 Cを桁DPでも解いてみた

「桁DPで解きたくなる誘惑に負けず全探索で解くべき問題」ABC 114 Cを、後学のために桁DPでも解いてみたメモ。
本番では3,5,7のみで出来た9桁までの数を全列挙しました

桁DPのアイデアと実装については桁DP入門 - pekempey's blog がとても参考になります。

状態はどう持てばいいか

  • 何桁目まで見たか (0..\lceil\log_{10} N\rceil)
  • N未満か (0..1)
  • 3を既に含んでいるか (0..1)
  • 5を既に含んでいるか (0..1)
  • 7を既に含んでいるか (0..1)
  • 357以外を含んでいるか (0..1)
  • 0より大きいか (0..1)

「0より大きいか」というか、leading zeroを非753数字としてカウントしないフラグが必要。。(これに気づかなくてちょっと時間かかった。本番でやったらはまってただろう)
→AC
https://beta.atcoder.jp/contests/abc114/submissions/3711407

#include <bits/stdc++.h>
using namespace std;
#define rep(var, n) for (int var = 0; var < (n); ++var)

vector<int> num_to_vec(int x, int base = 10) {
    if (x == 0) return vector<int>{0};
    vector<int> v;
    while (x) {
        int q = x / base, r = x % base;
        v.push_back(r);
        x = q;
    }
    reverse(v.begin(), v.end());
    return v;
}

int solve(int N) {
    vector<int> a = num_to_vec(N, 10);
    int K = a.size();

    int dp[K + 1][2][2][2][2][2][2];
    mset(dp, 0);

    dp[0][0][0][0][0][0][0] = 1;

    rep(i, K) rep(j, 2) rep(k, 2) rep(l, 2) rep(m, 2) rep(n, 2) rep(o, 2) {
        int lim = j ? 9 : a[i];
        rep(d, lim + 1) {
            bool non357 = n ? (d != 3 && d != 5 && d != 7)
                            : (d != 0 && d != 3 && d != 5 && d != 7);
            dp[i + 1][j || d < lim][k || d == 7][l || d == 5][m || d == 3][n || d][o || non357]
               += dp[i][j][k][l][m][n][o];
        }
    }

    int ans = 0;
    rep(j, 2) rep(k, 2) rep(l, 2) rep(m, 2) rep(n, 2) rep(o, 2) {
        if (k == 1 && l == 1 && m == 1 && o == 0) ans += dp[K][j][k][l][m][n][o];
    }
    return ans;
}

int main() {
    int N;
    cin >> N;
    cout << solve(N) << endl;
    return 0;
}