0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AtCoder Educational DP Contest S問題解いてみた

Posted at

AtCoder Educational DP Contest S問題解いてみた

今回の問題

問題文

$1$ 以上 $K$ 以下の整数のうち、十進表記における各桁の数字の総和が $D$ の倍数であるようなものは何個でしょうか?
$10^9 + 7$ で割った余りを求めてください。

制約

  • 入力はすべて整数である。
  • $1 \leq K < 10^{10000}$
  • $1 \leq D \leq 100$

回答

#include <bits/stdc++.h>
using namespace std;

const int MOD = 1e9 + 7;

// dp[桁数][未満フラグ][余り]
// 最大10000桁なので、メモリ制限に注意しつつ確保
long long dp[10005][2][100];

int main() {
    string K;
    int D;
    cin >> K >> D;

    int n = K.size();

    // 初期化
    // 0桁目、まだKと一致(smaller=0)、余り0 の状態が1通り
    dp[0][0][0] = 1;

    for (int i = 0; i < n; i++) {
        // 文字列Kのi文字目を数値に変換
        int limit = K[i] - '0';

        for (int smaller = 0; smaller < 2; smaller++) {
            for (int rem = 0; rem < D; rem++) {
                // その状態に到達不可能な場合はスキップ
                if (dp[i][smaller][rem] == 0) continue;

                // 次の桁に置ける数字 x の範囲を決める
                // smaller=1 (すでにK未満確定) なら 0~9
                // smaller=0 (Kと一致中) なら 0~limit
                int upper = (smaller == 1) ? 9 : limit;

                for (int x = 0; x <= upper; x++) {
                    // 次の smaller 状態
                    // すでに smaller=1 なら 1 のまま
                    // まだ smaller=0 でも、今回 limit より小さい数(x < limit)を選べば 1 になる
                    int next_smaller = smaller;
                    if (smaller == 0 && x < limit) {
                        next_smaller = 1;
                    }

                    // 次の余り状態
                    int next_rem = (rem + x) % D;

                    // 遷移
                    dp[i + 1][next_smaller][next_rem] = (dp[i + 1][next_smaller][next_rem] + dp[i][smaller][rem]) % MOD;
                }
            }
        }
    }

    // 答えは N桁目まで見たときの、smaller=0と1両方の、余りが0のもの
    long long ans = (dp[n][0][0] + dp[n][1][0]) % MOD;

    // 0を含んでしまっているので1引く
    // (ただし、負の数にならないようにMODを足してから割る)
    ans = (ans - 1 + MOD) % MOD;

    cout << ans << endl;

    return 0;
}

自分なりの解説

dp[i][smaller][rem]を上からi桁目、smallerで上限の制約を受けるかどうか、remで余りを設定している。上からi桁目まではわかったが、smallerとremは回答を見ないとわからなかった。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?