QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#116711#6522. Digit ModeITMO_pengzoo#AC ✓366ms33176kbC++209.0kb2023-06-29 21:07:162023-06-29 21:07:18

Judging History

你现在查看的是最新测评结果

  • [2023-08-10 23:21:45]
  • System Update: QOJ starts to keep a history of the judgings of all the submissions.
  • [2023-06-29 21:07:18]
  • 评测
  • 测评结果:AC
  • 用时:366ms
  • 内存:33176kb
  • [2023-06-29 21:07:16]
  • 提交

answer

//  Nikita Golikov, 2023

#include <bits/stdc++.h>

using namespace std;

using uint = unsigned int;
using ll = long long;
using ull = unsigned long long;

#ifdef GOLIKOV
  #include "/Users/golikovnik/contests/debug.h"
#else
  #define debug(...) ;
#endif

template <class A, class B>
bool smin(A& x, B&& y) {
  if (y < x) {
    x = y;
    return true;
  }
  return false;
}

template <class A, class B>
bool smax(A& x, B&& y) {
  if (x < y) {
    x = y;
    return true;
  }
  return false;
}

//  by https://codeforces.com/profile/Nyaan
//  example submission:
//  https://codeforces.com/contest/1603/submission/133688639
template <uint32_t mod>
struct LazyMontgomeryModInt {
  using mint = LazyMontgomeryModInt;
  using i32 = int32_t;
  using u32 = uint32_t;
  using u64 = uint64_t;
 
  static constexpr u32 get_r() {
    u32 ret = mod;
    for (i32 i = 0; i < 4; ++i) ret *= 2 - mod * ret;
    return ret;
  }
 
  static constexpr u32 r = get_r();
  static constexpr u32 n2 = -u64(mod) % mod;
  static_assert(r * mod == 1, "invalid, r * mod != 1");
  static_assert(mod < (1 << 30), "invalid, mod >= 2 ^ 30");
  static_assert((mod & 1) == 1, "invalid, mod % 2 == 0");
 
  u32 a;
 
  constexpr LazyMontgomeryModInt() : a(0) {}
  constexpr LazyMontgomeryModInt(const int64_t &b)
      : a(reduce(u64(b % mod + mod) * n2)){};
 
  static constexpr u32 reduce(const u64 &b) {
    return (b + u64(u32(b) * u32(-r)) * mod) >> 32;
  }
 
  constexpr mint &operator+=(const mint &b) {
    if (i32(a += b.a - 2 * mod) < 0) a += 2 * mod;
    return *this;
  }

  constexpr mint &operator++() {
    return *this += 1;
  }

  constexpr mint operator++(int) {
    auto ret = *this;
    *this += 1;
    return ret;
  }

  constexpr mint &operator-=(const mint &b) {
    if (i32(a -= b.a) < 0) a += 2 * mod;
    return *this;
  }

  constexpr mint &operator--() {
    return *this -= 1;
  }

  constexpr mint operator--(int) {
    auto ret = *this;
    *this -= 1;
    return ret;
  }
 
  constexpr mint &operator*=(const mint &b) {
    a = reduce(u64(a) * b.a);
    return *this;
  }
 
  constexpr mint &operator/=(const mint &b) {
    *this *= b.inv();
    return *this;
  }
 
  constexpr friend mint operator+(mint a, const mint &b) { return a += b; }
  constexpr friend mint operator-(mint a, const mint &b) { return a -= b; }
  constexpr friend mint operator*(mint a, const mint &b) { return a *= b; }
  constexpr friend mint operator/(mint a, const mint &b) { return a /= b; }
  constexpr friend bool operator==(mint const& a, const mint &b) {
    return (a.a >= mod ? a.a - mod : a.a) == (b.a >= mod ? b.a - mod : b.a);
  }
  constexpr friend bool operator!=(mint const& a, const mint &b) {
    return (a.a >= mod ? a.a - mod : a.a) != (b.a >= mod ? b.a - mod : b.a);
  }
  constexpr friend bool operator<(mint const& a, const mint &b) {
    return (a.a >= mod ? a.a - mod : a.a) < (b.a >= mod ? b.a - mod : b.a);
  }
  constexpr mint operator-() const { return mint() - mint(*this); }
 
  constexpr mint power(u64 n) const {
    mint ret(1), mul(*this);
    while (n > 0) {
      if (n & 1) ret *= mul;
      mul *= mul;
      n >>= 1;
    }
    return ret;
  }
  
  constexpr mint inv() const { return power(mod - 2); }
 
  friend ostream &operator<<(ostream &os, const mint &b) {
    return os << b.get();
  }
 
  friend istream &operator>>(istream &is, mint &b) {
    int64_t t;
    is >> t;
    b = LazyMontgomeryModInt<mod>(t);
    return (is);
  }
  
  constexpr u32 get() const {
    u32 ret = reduce(a);
    return ret >= mod ? ret - mod : ret;
  }

  constexpr explicit operator int() const {
    return int(get());
  }

  constexpr explicit operator bool() const {
    return bool(get());
  }
 
  static constexpr u32 get_mod() { return mod; }
};
 
template <typename T>
struct Binomial {
  vector<T> f, g, h;
  Binomial(int CMAX = 0) : f(1, T(1)), g(1, T(1)), h(1, T(1)) {
    extend(CMAX + 1);    
  }

  void extend(int m) {
    int n = f.size();

    if (n >= m) {
      return;
    }

    f.resize(m);
    g.resize(m);
    h.resize(m);
    for (int i = n; i < m; i++) f[i] = f[i - 1] * T(i);
    g[m - 1] = f[m - 1].inv();
    h[m - 1] = g[m - 1] * f[m - 2];
    for (int i = m - 2; i >= n; i--) {
      g[i] = g[i + 1] * T(i + 1);
      h[i] = g[i] * f[i - 1];
    } 
  }

  void extend() {
    extend(2 * f.size());
  }
 
  T fact(int i) {
    if (i < 0) return T(0);
    while (i >= (int)f.size()) extend();
    return f[i];
  }
 
  T ifact(int i) {
    if (i < 0) return T(0);
    while (i >= (int)g.size()) extend();
    return g[i];
  }
 
  T inv(int i) {
    if (i < 0) return -inv(-i);
    while (i >= (int)h.size()) extend();
    return h[i];
  }
 
  T C(int n, int r) {
    if (n < 0 || n < r || r < 0) return T(0);
    return fact(n) * ifact(n - r) * ifact(r);
  }
 
  inline T operator()(int n, int r) { return C(n, r); }
 
  template <typename I>
  T multinomial(const vector<I>& r) {
    static_assert(is_integral<I>::value == true);
    int n = 0;
    for (auto& x : r) {
      if(x < 0) return T(0);
      n += x;
    }
    T res = fact(n);
    for (auto& x : r) res *= ifact(x);
    return res;
  }
 
  template <typename I>
  T operator()(const vector<I>& r) {
    return multinomial(r);
  }
 
  T C_naive(int n, int r) {
    if (n < 0 || n < r || r < 0) return T(0);
    T ret = T(1);
    r = min(r, n - r);
    for (int i = 1; i <= r; ++i) ret *= inv(i) * (n--);
    return ret;
  }
 
  T A(int n, int r) {
    if (n < 0 || n < r || r < 0) return T(0);
    return fact(n) * ifact(n - r);
  }
 
  T CR(int n, int r) {
    if (n < 0 || r < 0) return T(0);
    return r == 0 ? 1 : C(n + r - 1, r);
  }
};
// int const MOD = 998244353;
int const MOD = int(1e9 + 7);
using mint = LazyMontgomeryModInt<MOD>;
Binomial<mint> C;

vector<mint> mkpow(mint base, int mx) {
  vector<mint> res(mx + 1);
  res[0] = 1;
  for (int i = 1; i <= mx; ++i) {
    res[i] = res[i - 1] * base;
  }
  return res;
}

int const MAX = 51;
mint dp[11][MAX][MAX][10];
int const MASIZE = 7;
int const MA = int(1e6);
mint precalc[MA][MAX];
bool havePrecalc[MA][MAX];
mint CC[MAX][MAX];

void solveTest() {
  string r; cin >> r;
  int p = int(r.size()) - 1;
  while (p >= 0 && r[p] == '9') {
    r[p--] = '0';
  }
  if (p < 0) {
    r.insert(r.begin(), '1');
  } else {
    r[p]++;
  }

  auto solve = [&](string upto) {
    mint res = 0;
    auto go = [&](string pref, int left) {
      if (pref.size() < MASIZE && havePrecalc[atoi(pref.c_str())][left]) {
        res += precalc[atoi(pref.c_str())][left];
        return;
      }
      int cnt[10]{};
      for (char ch : pref) {
        cnt[ch - '0']++;
      }
      memset(dp, 0, sizeof dp);
      dp[0][0][0][0] = 1;
      for (int d = 0; d < 10; ++d) {
        for (int x = 0; x <= left; ++x) {
          for (int c = 0; c < MAX; ++c) {
            for (int bd = 0; bd <= d; ++bd) {
              auto val = dp[d][x][c][bd];
              if (!val) {
                continue;
              }
              for (int t = max(0, c - cnt[d]); t + x <= left; ++t) {
                dp[d + 1][t + x][cnt[d] + t][d] += val * CC[t + x][x];
              }
              for (int t = 0; t < c - cnt[d] && t + x <= left; ++t) {
                dp[d + 1][t + x][c][bd] += val * CC[t + x][x];
              }
            }
          }
        }
      }
      mint here = 0;
      for (int i = 0; i < MAX; ++i) {
        for (int d = 0; d < 10; ++d) {
          here += dp[10][left][i][d] * d;
        }
      }
      res += here;
      if (pref.size() < MASIZE) {
        precalc[atoi(pref.c_str())][left] = here;
        havePrecalc[atoi(pref.c_str())][left] = true;
      }
    };

    auto s = upto;
    int len = int(s.size());
    vector<mint> pw(len + 1);
    pw[0] = 1;
    for (int i = 1; i <= len; ++i) {
      pw[i] = pw[i - 1] * 10;
    }
    string pref;
    for (int i = 0; i < len; ++i) {
      int here = s[i] - '0';
      for (int d = !i; d < here; ++d) {
        pref.push_back(char('0') + d);
        go(pref, len - i - 1);
        pref.pop_back();
      }
      if (i > 0) {
        for (int d = 1; d < 10; ++d) {
          go(to_string(d), len - i - 1);
        }
      }
      pref.push_back(char('0') + here);
    }
    return res;
  };

  cout << solve(r) << '\n';
}

int main() {
#ifdef GOLIKOV
  assert(freopen("in", "rt", stdin));
  auto _clock_start = chrono::high_resolution_clock::now();
#endif
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  for (int i = 0; i < MAX; ++i) {
    CC[i][0] = 1;
    for (int j = 1; j <= i; ++j) {
      CC[i][j] = CC[i - 1][j - 1] + CC[i - 1][j];
    }
  }

  int tests_;
  cin >> tests_;
  for (int tt_ = 1; tt_ <= tests_; ++tt_) {
    solveTest();
  }

#ifdef GOLIKOV
  cerr << "Executed in " << chrono::duration_cast<chrono::milliseconds>(
      chrono::high_resolution_clock::now()
          - _clock_start).count() << "ms." << endl;
#endif
  return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 4ms
memory: 6588kb

input:

5
9
99
999
99999
999999

output:

45
615
6570
597600
5689830

result:

ok 5 number(s): "45 615 6570 597600 5689830"

Test #2:

score: 0
Accepted
time: 1ms
memory: 6688kb

input:

34
7
48
8
76
1
97
7
5
7
7
2
89
9
4
84
46
6
73
86
78
5
3
8
9
31
24
78
7
11
45
2
65
88
6

output:

28
236
36
420
1
597
28
15
28
28
3
525
45
10
484
221
21
399
500
435
15
6
36
45
145
104
435
28
47
215
3
341
516
21

result:

ok 34 numbers

Test #3:

score: 0
Accepted
time: 5ms
memory: 6636kb

input:

16
935
888
429
370
499
881
285
162
178
948
205
858
573
249
773
615

output:

6009
5618
2456
2078
2905
5562
1603
887
993
6121
1174
5378
3333
1374
4724
3631

result:

ok 16 numbers

Test #4:

score: 0
Accepted
time: 3ms
memory: 8816kb

input:

12
1242
9985
6469
9310
4191
9497
3166
3495
9711
9698
4137
2257

output:

7292
63531
37910
58047
23987
59479
18076
19675
61184
61086
23672
12913

result:

ok 12 numbers

Test #5:

score: 0
Accepted
time: 0ms
memory: 18464kb

input:

10
61195
72739
10164
79164
57851
12326
29132
55992
67377
13873

output:

337575
408170
63792
450686
316513
70493
157773
305011
374163
77954

result:

ok 10 numbers

Test #6:

score: 0
Accepted
time: 9ms
memory: 33176kb

input:

8
529983
127270
421121
291729
461233
695056
365028
271160

output:

2744573
687141
2160067
1500426
2359204
3705475
1851172
1381981

result:

ok 8 numbers

Test #7:

score: 0
Accepted
time: 7ms
memory: 25092kb

input:

7
7934351
8474057
1287369
5845624
7796773
5805755
7349121

output:

42465725
45668947
6716401
30094426
41554096
29861098
38756757

result:

ok 7 numbers

Test #8:

score: 0
Accepted
time: 27ms
memory: 21008kb

input:

3
5014252832385738
8762796162648653
919997886706385

output:

892033338
297722019
462512414

result:

ok 3 number(s): "892033338 297722019 462512414"

Test #9:

score: 0
Accepted
time: 46ms
memory: 16372kb

input:

2
775701797726112292362823101
75927988177061355614

output:

371275551
566830847

result:

ok 2 number(s): "371275551 566830847"

Test #10:

score: 0
Accepted
time: 278ms
memory: 12400kb

input:

1
65760982925996012426370962570581226245366145016666

output:

661063035

result:

ok 1 number(s): "661063035"

Test #11:

score: 0
Accepted
time: 285ms
memory: 12748kb

input:

1
62597468169905757754175023836706426691470692832490

output:

9983261

result:

ok 1 number(s): "9983261"

Test #12:

score: 0
Accepted
time: 291ms
memory: 14452kb

input:

1
78912847369504885593964702297317051208901751786824

output:

817123221

result:

ok 1 number(s): "817123221"

Test #13:

score: 0
Accepted
time: 186ms
memory: 6624kb

input:

1
99999999999999999999999999999999999999999999999999

output:

25251932

result:

ok 1 number(s): "25251932"

Test #14:

score: 0
Accepted
time: 132ms
memory: 8516kb

input:

1
999999999999999999999999999999999999999999999

output:

439421821

result:

ok 1 number(s): "439421821"

Test #15:

score: 0
Accepted
time: 87ms
memory: 7960kb

input:

1
9999999999999999999999999999999999999999

output:

387537647

result:

ok 1 number(s): "387537647"

Test #16:

score: 0
Accepted
time: 360ms
memory: 10704kb

input:

1
99999999999999999999999998889999898988888889998888

output:

909431898

result:

ok 1 number(s): "909431898"

Test #17:

score: 0
Accepted
time: 366ms
memory: 12776kb

input:

1
99999999999999999999999998989899988889989889999888

output:

289727470

result:

ok 1 number(s): "289727470"

Test #18:

score: 0
Accepted
time: 365ms
memory: 12588kb

input:

1
99999999999999999999999998998988898888898889898999

output:

962896416

result:

ok 1 number(s): "962896416"

Test #19:

score: 0
Accepted
time: 177ms
memory: 10764kb

input:

1
9999999999999999999989988898888989888899

output:

995903330

result:

ok 1 number(s): "995903330"

Test #20:

score: 0
Accepted
time: 180ms
memory: 10768kb

input:

1
9999999999999999999989999889889998998898

output:

385460258

result:

ok 1 number(s): "385460258"

Test #21:

score: 0
Accepted
time: 185ms
memory: 6592kb

input:

1
99999999999999999999999999999999999999999999999999

output:

25251932

result:

ok 1 number(s): "25251932"