E - Simple Division

E - Simple Division

Problem Statement

You are given integers $N$ and $M$. Find the remainder when $\lfloor N/M \rfloor$ is divided by $\color{red}{10007}$.
Here, $\lfloor x \rfloor$ denotes the largest integer not exceeding $x$. For example, $\lfloor 3.14 \rfloor=3$ and $\lfloor 10 \rfloor = 10$.

In this problem, $N$ is not given directly; instead, it is given in run-length encoded form.
Specifically, $N$ is represented by a sequence of $K$ pairs of a digit $c_i$ and an integer $l_i$.
To recover the original $N$, use the following procedure.

  • Initially, let string $S$ be the empty string.
  • For $i=1,2,\dots,K$, repeat the following.
    • Append $l_i$ copies of digit $c_i$ to the end of $S$.
  • Interpret the final $S$ as a single integer; that integer is $N$.

Constraints

  • $1 \le M \le 10^4$
  • $1 \le K \le 10^5$
  • $c_i$ is one of the digits $0,1,2,3,4,5,6,7,8,9$.
  • $1 \le l_i \le 10^9$
  • $c_1 \neq 0$
  • $M,K,l_i$ are integers.

Input

The input is given from Standard Input in the following format:

$K$ $M$
$c_1$ $l_1$
$c_2$ $l_2$
$\vdots$
$c_K$ $l_K$

Output

Output the answer.


Sample Input 1

6 7
3 1
1 1
6 1
2 2
7 2
6 2

Sample Output 1

3797

In this input, $N=316227766$ and $M=7$.
$\lfloor 316227766/7 \rfloor = 45175395$, and the remainder when this is divided by $10007$ is $3797$, which is the final answer.


Sample Input 2

1 1
1 1

Sample Output 2

1

Sample Input 3

10 9999
9 419921892
9 923650333
6 476449815
1 8837775
2 141135534
5 462618481
3 202652735
0 771538044
4 321458589
0 570032864

Sample Output 3

8437

 

解题思路

  这题学到很多东西,来记录一下。先给出我赛时的傻逼做法。

  首先 $n$ 是一个非常巨大的数,无法通过直接拼接数位来表示。相反,我们可以将其转化为每个数位的贡献之和,即 $n = \sum\limits_{i=1}^{k}c_i \times \frac{10^{l_i} - 1}{9} \times 10^{\sum_{j=i+1}^{k}{l_j}}$。由带余除法 $n = \left\lfloor\tfrac{n}{m}\right\rfloor m + (n \bmod m)$,可得 $\left\lfloor\tfrac{n}{m}\right\rfloor = \tfrac{n - (n \bmod m)}{m}$。由于 $0 < m < 10007$ 且 $10007$ 是质数,因此 $\left\lfloor\tfrac{n}{m}\right\rfloor \equiv \tfrac{n - (n \bmod m)}{m} \pmod{10007}$。

  然而在计算 $n \bmod m$ 时,由于 $9$ 可能与 $m$ 不互质,导致无法计算 $\frac{10^{l_i} - 1}{9}$ 中 $9$ 的逆元。但注意到 $\frac{10^{l_i} - 1}{9} = \sum\limits_{j=0}^{l_i-1}{10^j}$ 必定为整数,因此我们可以通过计算等比数列和的方式来规避除法。

  一般地,定义 $P(a, k) = \sum\limits_{i=0}^{k}{a^i}$。考虑 $k$ 为奇数的情况,此时可将求和项拆分为前后两半:$\sum\limits_{i=0}^{k}{a^i} = \sum\limits_{i=0}^{\left\lfloor k/2 \right\rfloor}{a^i} + \sum\limits_{i=\left\lfloor k/2 \right\rfloor + 1}^{k}{a^i}$。后半部分提取公因式后等价于 $a^{\left\lfloor k/2 \right\rfloor + 1}\sum\limits_{i=0}^{\left\lfloor k/2 \right\rfloor}{a^i}$。因此有 $P(a, k) = \left(1 + a^{\left\lfloor k/2 \right\rfloor + 1} \right) P\left(a, \left\lfloor \frac{k}{2} \right\rfloor\right)$。通过该递推关系,可在 $O(\log{k})$ 的时间复杂度内得到结果。

  若 $k$ 为偶数,则将 $a^0 = 1$ 单独提出,转化为 $k-1$ 为奇数的情况,有 $P(a, k) = 1 + a \cdot P(a, k-1)$。

  综上所述,先计算 $n \bmod m$ 记作 $r$,再计算 $n \bmod 10007$ 记作 $r'$,则 $\frac{r' - r}{M} \bmod 10007$ 即为答案。

  AC 代码如下,时间复杂度为 $O(k \log^2{\max{l_i}})$:

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

typedef long long LL;

const int N = 1e5 + 5, mod = 10007;

int n, m;
int c[N], l[N];

int qmi(int a, int k, int mod) {
    int ret = 1;
    while (k) {
        if (k & 1) ret = 1ll * ret * a % mod;
        a = 1ll * a * a % mod;
        k >>= 1;
    }
    return ret;
}

int dfs(int a, int k, int mod) {
    if (!k) return 1;
    if (k & 1) return (1ll + qmi(a, k / 2 + 1, mod)) * dfs(a, k / 2, mod) % mod;
    return (1 + 1ll * a * dfs(a, k - 1, mod)) % mod;
}

int get(int mod) {
    int ret = 0;
    for (int i = n, p = 1; i; i--) {
        ret = (ret + 1ll * c[i] * dfs(10, l[i] - 1, mod) % mod * p) % mod;
        p = 1ll * p * qmi(10, l[i], mod) % mod;
    }
    return ret;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> c[i] >> l[i];
    }
    cout << LL(get(mod) - get(m) + mod) * qmi(m, mod - 2, mod) % mod;
    
    return 0;
}

  再给出官方题解的做法。记 $r = n \bmod (m \times 10007)$,则 $\left\lfloor\tfrac{n}{m}\right\rfloor \bmod 10007$ 等于 $\left\lfloor\tfrac{r}{m}\right\rfloor$。下面证明 $\left\lfloor\tfrac{n}{m}\right\rfloor\bmod p=\left\lfloor\tfrac{n \bmod (m \times p)}{m}\right\rfloor$。

  由关于 $m$ 的带余除法得到 $m = \left\lfloor\frac{n}{m}\right\rfloor m + (n \bmod m)$,继续对 $\left\lfloor\tfrac{n}{m}\right\rfloor$ 关于 $p$ 进行带余除法得到 $\left\lfloor\tfrac{n}{m}\right\rfloor = \left\lfloor\tfrac{n}{m \times p}\right\rfloor p + \left(\left\lfloor\tfrac{n}{m}\right\rfloor \bmod p\right)$。代入前式可得 $n = \left\lfloor\tfrac{n}{m \times p}\right\rfloor p \times m + \left(\left\lfloor\tfrac{n}{m}\right\rfloor \bmod p\right) m + (n \bmod m)$。由于 $0 \le \left(\left\lfloor\tfrac{n}{m}\right\rfloor \bmod p\right) m + (n \bmod m) \le (p-1)m + m-1 = p \times m - 1$,根据带余除法的唯一性,该式即为 $n$ 除以 $m \times p$ 的余数。

  将该余数代入 $\left\lfloor\tfrac{n \bmod (m \times p)}{m}\right\rfloor$,得到 $$\begin{align*} &\left\lfloor\frac{\left(\left\lfloor\frac{n}{m}\right\rfloor \bmod p\right) m + (n \bmod m)}{m}\right\rfloor \\ =&\frac{\left(\left\lfloor\frac{n}{m}\right\rfloor \bmod p\right) m}{m} + \left\lfloor\frac{n \bmod m}{m}\right\rfloor \\=&\left\lfloor\frac{n}{m}\right\rfloor \bmod p \end{align*}$$

  证毕。因此,我们只需计算 $\sum\limits_{i=1}^{k} c_i \times P(10, l_i-1) \times 10^{\sum_{j=i+1}^{k}{l_j}} \bmod (m \times 10007)$,记结果为 $r$,则 $\left\lfloor\tfrac{r}{m}\right\rfloor$ 即为所求。

  另外,再提供另外一种求 $P(a, k) = \sum\limits_{i=0}^{k}{a^i}$ 的方法,用到倍增的思想。考虑项数为 $2$ 的次幂的形式,若已知 $Q\left(a, 2^k\right) = \sum\limits_{i=0}^{2^k-1}{a^i}$,则有 $$Q\left(a, 2^{k+1}\right) = \sum\limits_{i=0}^{2^{k+1}-1}{a^i} = \sum\limits_{i=0}^{2^k-1}{a^i} + a^{2^k}\sum\limits_{i=0}^{2^k-1}{a^i} = \left(1 + a^{2^k}\right) Q\left(a, 2^k\right)$$

  若要求 $Q(a, n)$,只需将 $n$ 表示为二进制形式 $n = 2^{\alpha_1}+2^{\alpha_2}+\cdots+2^{\alpha_k}$,则有 $Q(a, n) = \sum\limits_{i=1}^{k}{Q\left(a, 2^{\alpha_i}\right) \prod\limits_{j=i + 1}^{k}{a^{2^{\alpha_j}}}}$。

  AC 代码如下,时间复杂度为 $O(k \log{\max{l_i}})$:

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

typedef long long LL;

const int N = 1e5 + 5, mod = 10007;

int c[N], l[N];

int qmi(int a, int k, int mod) {
    int ret = 1;
    while (k) {
        if (k & 1) ret = 1ll * ret * a % mod;
        a = 1ll * a * a % mod;
        k >>= 1;
    }
    return ret;
}

int get(int a, int k, int mod) {
    int ret = 0, p = 1;
    while (k) {
        if (k & 1) ret = (1ll * ret * a + p) % mod;
        p = (1ll * p * a + p) % mod;
        a = 1ll * a * a % mod;
        k >>= 1;
    }
    return ret;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> c[i] >> l[i];
    }
    int ret = 0;
    for (int i = n, p = 1; i; i--) {
        ret = (ret + 1ll * c[i] * get(10, l[i], m * mod) % (m * mod) * p) % (m * mod);
        p = 1ll * p * qmi(10, l[i], m * mod) % (m * mod);
    }
    ret /= m;
    cout << ret;
    
    return 0;
}

  2026-03-09 更新,补充做法。

  事实上,对于第二种做法,若直接代入 $n$ 的表达式计算 $n \bmod (m \times 10007)$,正如第一种做法所述,$9$ 可能与 $m \times 10007$ 不互质,导致无法求解逆元。此时可将 $n$ 看作 $\tfrac{\sum\limits_{i=1}^{k}c_i \times \left(10^{l_i} - 1\right) \times 10^{\sum_{j=i+1}^{k}{l_j}}}{9}$,问题转化为求该分数模 $m \times 10007$ 的值。再次运用结论 $\left\lfloor\tfrac{n}{m}\right\rfloor\bmod p=\left\lfloor\tfrac{n \bmod (m \times p)}{m}\right\rfloor$,我们只需计算分子部分对 $9 \times m \times 10007$ 取模的结果,记作 $r$。那么 $\left\lfloor\tfrac{r}{9}\right\rfloor$ 即为 $n \bmod (m \times 10007)$,进而 $\left\lfloor\tfrac{r}{9 \times m}\right\rfloor$ 即为最终答案 $\left\lfloor\tfrac{n}{m}\right\rfloor \bmod 10007$。

  AC 代码如下,时间复杂度为 $O(k \log{\max{l_i}})$:

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

typedef long long LL;

const int N = 1e5 + 5, mod = 10007;

int c[N], l[N];

int qmi(int a, int k, int mod) {
    int ret = 1;
    while (k) {
        if (k & 1) ret = 1ll * ret * a % mod;
        a = 1ll * a * a % mod;
        k >>= 1;
    }
    return ret;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> c[i] >> l[i];
    }
    int ret = 0;
    for (int i = n, p = 1; i; i--) {
        int t = qmi(10, l[i], 9 * m * mod);
        ret = (ret + c[i] * (t - 1ll) % (9 * m * mod) * p) % (9 * m * mod);
        p = 1ll * p * t % (9 * m * mod);
    }
    ret /= 9 * m;
    cout << ret;
    
    return 0;
}

 

参考资料

  Editorial - AtCoder Beginner Contest 448:https://atcoder.jp/contests/abc448/editorial/16989

  Editorial - AtCoder Beginner Contest 448:https://atcoder.jp/contests/abc448/editorial/16984

posted @ 2026-03-08 23:05  onlyblues  阅读(4)  评论(0)    收藏  举报
Web Analytics