memo[桁数][最後に使った数][ここまでの余り][増加or減少][与えられた数より小さくなったかどうか]
筆算をする。
[与えられた数より小さくなったかどうか]はつまり、ここまで作った数字のプレフィックスが一致しているかどうか。
D桁目まで一致しているのであれば、次の数字は与えられた数NのD+1桁目以下でなければならない。
この制約があることで、ある数N以下で条件を満たす個数が分かる。
既に一致していない場合は、D+1桁目より大きな数を選んでもよい。
(y - x + mod) % mod を忘れると答えが負になることがある。これで相当悩んだ。
- #include <iostream>
- #include <algorithm>
- #include <vector>
- using namespace std;
- const int MOD = 500 + 1;
- const int LEN = 500 + 1;
- const int LAST = 10;
- const int A = 2;
- const int P = 2;
- int t[LEN][LAST][MOD][A][P];
- int M;
- int lim;
- string str;
- const int mod = 10000;
- int rec(int len, int last, int carry, bool a, bool p)
- {
- if (len == lim) return carry == 0;
- if (t[len][last][carry][a][p] != -1) return t[len][last][carry][a][p];
- int sum = 0;
- int b, e;
- if (a) b = last + 1, e = 10;
- else b = 0, e = last;
- for (int n = b; n < e; ++n) {
- int m = (carry * 10 + n) % M;
- if (p) {
- if (str[len + 1] - '0' >= n) {
- sum += rec(len + 1, n, m, a^1, (str[len + 1] - '0') == n);
- }
- } else sum += rec(len + 1, n, m, a^1, false);
- sum %= mod;
- }
- return t[len][last][carry][a][p] = sum;
- }
- int calc(string s)
- {
- fill(&t[0][0][0][0][0], &t[LEN - 1][LAST - 1][MOD - 1][A - 1][P], -1);
- int sum = 0;
- lim = (int)s.size() - 1;
- str = s;
- for (int i = 1; i <= s[0] - '0'; ++i) {
- if (lim) {
- sum += rec(0, i, i%M, 0, s[0] - '0' == i);
- sum %= mod;
- }
- sum += rec(0, i, i%M, 1, s[0] - '0' == i);
- sum %= mod;
- }
- for (int i = 1; i <= lim; ++i) {
- for (int j = 1; j < 10; ++j) {
- if (i != lim) {
- sum += rec(i, j, j%M, 0, false);
- sum %= mod;
- }
- sum += rec(i, j, j%M, 1, false);
- sum %= mod;
- }
- }
- return sum;
- }
- string minus1(string s)
- {
- if (s.size() == 1) { --s[0]; return s; }
- for (int i = (int)s.size() - 1; i; --i) {
- --s[i];
- if ('0' <= s[i]) break;
- else {
- s[i] = '9';
- --s[i - 1];
- }
- }
- while (s[0] == '0' && s.size()) s = s.substr(1);
- return s;
- }
- int main(int argc, char *argv[])
- {
- string u, v;
- while (cin >> u >> v >> M) {
- int y = calc(v);
- int x = calc(minus1(u));
- cout << (y - x + mod) % mod << endl;
- }
- return 0;
- }
0 件のコメント :
コメントを投稿