【AtCoder】ABC 460 E - x + y ≡ x + y

E - x + y ≡ x + yatcoder.jp favicon

実行時間制限: 2 sec / メモリ制限: 1024 MiB / Difficulty: 1362 / NoviSteps: 1D / 配点: 450

問題概要

正整数 a,ba,b に対して、aabb を文字列と見なしてこの順に連結して書いた時に出来る整数を concat(a,b)\mathrm{concat}(a, b) と呼ぶことにする。

正整数 N,MN, M が与えられるとき、NN 以下の正整数の組 (x,y)(x,y) であって concat(x,y)x+y(modM)\mathrm{concat}(x, y) \equiv x + y \pmod{M} であるものの個数を 998244353998244353 で割った余りを求めよ。

TT 個のテストケースが与えられるので、それぞれについて答えを求めること。

制約

  • 1T1041 \leq T \leq 10^4
  • 1N10181 \leq N \leq 10^{18}
  • 2M1092 \leq M \leq 10^9
  • 入力される値は全て整数

考察

とりあえず、問題条件を数式で表してみる。 yy の桁数を dd とすると、

concat(x,y)x+y(modM)x10d+yx+y(modM)x(10d1)0(modM)\begin{align} \mathrm{concat}(x, y) &\equiv x + y \pmod{M} \notag \\ x \cdot 10^d + y &\equiv x + y \pmod{M}\notag \\ x (10^d - 1) &\equiv 0 \pmod{M} \end{align}

となる。

(1)(1) より, 求める条件は xxdd についてのみ依存することが分かる。

ここで、 1yN10181 \leq y \leq N \leq 10^{18} であることから dd は最大で 1919 なので、以下では dd を固定したときの xx の条件について考えることにしよう。

dd を固定したときの xx の個数

(1)(1) を以下のように言い換える。 なお、 aba \mid bbbaa の倍数であることを表す。

Mx(10d1)\begin{equation} M \mid x(10^d - 1) \end{equation}

今は xx に関する条件を考えているので、右側を xx だけで表したい。 そこで、 A=10d1A = 10^d - 1 として g=gcd(M,A)g = \gcd(M, A) を考えると、 M=gMM = g M'A=gAA = g A' と表せる。 すると、式 (2)(2) は以下のように変形できる。

MxA    gMxgA    MxA\begin{align*} M \mid x A & \iff g M' \mid x \cdot g A' \notag \\ & \iff M' \mid x \cdot A' \notag \\ \end{align*}

MM'AA' は互いに素であるため、 MM' の素因数は全て xx 側に含まれていなければならない。 したがって、

Mx    Mgcd(M,10d1)x\begin{equation} M' \mid x \iff \left. \dfrac{M}{\gcd(M, 10^d - 1)} \right| x \end{equation}

が成り立つ。

(3)(3) より、 Ld=Mgcd(M,10d1)L_d = \frac{M}{\gcd(M, 10^d - 1)} とおくと、 xx1xN1 \leq x \leq N を満たす LdL_d の倍数であるから、ある dd における条件を満たす xx の個数 cx(d)c_x(d) は、 NLd\left\lfloor \frac{N}{L_d} \right\rfloor と計算できる。

桁数が dd となるような yy の個数

yy の桁数が dd であるための条件は、 10d1y<10d10^{d - 1} \leq y < 10^d である。

しかし、これに加えて 1yN1 \leq y \leq N も満たす必要があるため、 yy の桁数が dd であるような yy の個数 cy(d)c_y(d) は、

cy(d)=max(0,min(N,10d1)10d1+1)c_y(d) = \max \left( 0, \min(N, 10^d - 1) - 10^{d - 1} + 1 \right)

と計算できる。


以上より、求める答えは以下のように計算できる。

d=119cx(d)cy(d)(mod998244353)\sum_{d = 1}^{19} c_x(d) \cdot c_y(d) \pmod{998244353}

実装上の注意点

今回の方針だと dd は最大 1919 まで登場するので、 101910^{19}long long 型だとオーバーフローしてしまう。 そこで、 10d10^dcy(d)c_y(d)__int128_t 型で計算する必要がある。

また、 LdL_d の式における gcd(M,10d1)\gcd(M, 10^d - 1) の計算については、

gcd(M,10d1)=gcd(M,10d1modM)\gcd(M, 10^d - 1) = \gcd(M, 10^d - 1 \bmod M)

が成り立つことを踏まえると、 ACL のpow_modを用いることによって long long 型のまま計算できる。

実装例

ACLのmod_intを使ってみたが、却ってごちゃごちゃしてしまった。

CPP
1.#include <bits/stdc++.h>
2.using namespace std;
3.
4.#if __has_include(<atcoder/all>)
5.#include <atcoder/all>
6.using namespace atcoder;
7.#endif
8.
9.#define repe(i, start, end) for (auto i = (start); (i) <= (end); (i)++)
10.
11.using ll = long long;
12.using mint = modint998244353;
13.
14.// ======================================== //
15.
16.using i128 = __int128_t;
17.constexpr int MOD = 998244353;
18.
19.ll solve() {
20. ll N, M;
21. cin >> N >> M;
22.
23. vector<i128> pow10(20);
24. pow10[0] = 1;
25. repe(i, 1, 19) {
26. pow10[i] = pow10[i - 1] * 10;
27. }
28.
29. mint ans = 0;
30.
31. repe(d, 1, 19) {
32. i128 right = min<i128>(N, pow10[d] - 1);
33. i128 cnt_y = max<i128>(0, right - pow10[d - 1] + 1);
34.
35. if (cnt_y == 0) continue;
36.
37. ll r = (pow_mod(10, d, M) - 1 + M) % M;
38. ll g = gcd(M, r);
39.
40. ll Ld = M / g;
41. ll cnt_x = N / Ld;
42.
43. ans += mint((ll)(cnt_y % MOD)) * mint(cnt_x % MOD);
44. }
45.
46. return ans.val();
47.}
48.
49.int main()
50.{
51. int T;
52. cin >> T;
53.
54. while (T--)
55. {
56. cout << solve() << endl;
57. }
58.
59. return 0;
60.}
Submission #76519323 - AtCoder Beginner Contest 460atcoder.jp favicon

実装時間: 50 分

コメント

(2)(2) から式 (3)(3) への変形の発想が難しい。