ABC 029

https://atcoder.jp/contests/abc029

A. 複数形

https://atcoder.jp/contests/abc029/tasks/abc029_a

B. カキ

https://atcoder.jp/contests/abc029/tasks/abc029_b

C. Brute-force Attack

https://atcoder.jp/contests/abc029/tasks/abc029_c

D. 1

https://atcoder.jp/contests/abc029/tasks/abc029_d

自力 AC だが桁 DP の問題ということをわかった上で解いた。

dp[i][is_less][c] を上位 $i$ 桁目までの数を見て $N$ 以下であることが確定(している is_less=1, していない is_less=0)かつ 1 の個数が c 個であるような数の個数とする。 dp[0][0][0] = 1 として、桁を進めていく。

void solve() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    string N;
    cin >> N;

    int sz = N.size();

    int mx = 15;
    vector dp(sz + 1, vector(2, vector<mint>(mx)));
    dp[0][0][0] = 1;

    rep2(i, 1, sz + 1) {
        int t = N[i - 1] - '0';
        rep(d, 10) {
            bool is_one = d == 1;
            rep(c, mx) {
                if (d < t) {
                    dp[i][1][c + is_one] += dp[i - 1][0][c];
                }
                if (d == t) {
                    dp[i][0][c + is_one] += dp[i - 1][0][c];
                }
                dp[i][1][c + is_one] += dp[i - 1][1][c];
            }
        }
    }

    mint ans = 0;
    rep2(c, 1, mx) {  // (N 未満の数で 1 の個数が c 個である数の個数) * c
        ans += dp[sz][1][c] * c;
    }
    for (char c : N) {  // N そのものの 1 の個数を数える
        if (c == '1') ans++;
    }
    cout << ans.val() << endl;
}