2026.06.01 作业 - # AT_abc460_e [ABC460E] x + y ≡ x + y

题目描述

对于正整数 \(a,b\),定义拼接运算 \(\mathrm{concat}(a,b)\)
\(a\)\(b\) 分别写作十进制字符串 \(A,B\),将字符串 \(A\) 后接字符串 \(B\) 得到新串 \(C\),把字符串 \(C\) 视作十进制整数,该数值即为 \(\mathrm{concat}(a,b)\)

举例:\(a=123,b=45\) 时,\(\mathrm{concat}(a,b)=12345\)

给定正整数 \(N,M\),求满足下述条件的正整数有序对 \((x,y)\) 的总数:
\(1\le x\le N,1\le y\le N\),且 \(\mathrm{concat}(x,y)\equiv x+y \pmod M\)
答案对 \(998244353\) 取余数。

共有 \(T\) 组测试用例,对每组输入分别输出答案。

输入格式

首行输入整数 \(T\),之后连续 \(T\) 行,每行两个整数 \(N、M\),代表一组询问。

输出格式

输出共 \(T\) 行,每行一个整数,为对应询问的合法数对数量模 \(998244353\) 的结果。

输入样例

4
3 2
123 456
20260530 460
123456789123456789 998244353

输出样例

3
0
922576091
422081792

样例说明

第一组 \(N=3,M=2\),合法数对:\((2,1),(2,2),(2,3)\),合计3组。

限制条件

  • \(1\le T \le 10^4\)
  • \(1\le N \le 10^{18}\)
  • \(2\le M \le 10^9\)
  • 所有输入数据均为整数

思考1 :表达式转换

题目要求满足 \(\text{concat}(x, y) \equiv x + y \pmod{M}\) 的数对 \((x, y)\) 个数,其中 \(1 \le x, y \le N\),$N $ 最大可达 \(10^{18}\)

\(d(y)\)表示 \(y\) 的十进制位数,拼接操作可表示为:

\[\text{concat}(x, y) = x \cdot 10^{d(y)} + y \]

代入原同余式并化简:

\[x \cdot 10^{d(y)} + y \equiv x + y \pmod{M} \]

\[x \cdot 10^{d(y)} \equiv x \pmod{M} \]

\[(10^{d(y)} - 1) \cdot x \equiv 0 \pmod{M} \]

思考2: 方案统计

上式表明,对于固定位数的 \(y\),需要找到所有满足条件的 \(x\)。根据同余理论,上述同余式等价于:

\[x \equiv 0 \pmod{\frac{M}{\gcd(M, 10^{d(y)} - 1)}} \]

因此,对于固定的位数 \(k = d(y)\)

  • \(x\) 的个数:是 \(\frac{M}{\gcd(M, 10^k - 1)}\)的倍数且不超过 \(N\),共有

    \[cntX = \left\lfloor \frac{N}{M / \gcd(M, 10^k - 1)} \right\rfloor \]

  • \(y\) 的个数:是 \(k\) 位数且不超过 \(N\) ,即为:位数为 \(k\) 的方案数 = $ min(n,10^k) >y \ge 10^{k-1}$

    \[cntY = \min(N, 10^k - 1) - 10^{k-1} + 1 \]

由于 \(N \le 10^{18}\),所以 \(d(y)\) 最大为 19。因此只需枚举 \(k\) 从 1 到 19,对每个 \(k\) 计算 \(cntX \times cntY\) 并求和即可。

参考代码

#include <bits/stdc++.h>
using namespace std;
#define ULL unsigned long long
const int MOD = 998244353;
ULL gcd(ULL a,ULL b) {
    return b?gcd(b,a%b):a;
}
int main() {
    int T; cin >> T;
    vector<ULL> p(20); // 预处理 10^k
    p[0] = 1; for(int i = 1; i <= 19; i++) p[i] = p[i - 1] * 10;
    while(T--){
        ULL N, M, ans = 0;
        cin >> N >> M;
        for(int k = 1; k <= 19; k++){
            if (p[k-1] > N) break; // 超出N的范围,直接退出
            ULL cntX = N /(M/gcd(M, p[k] - 1)); // x 的贡献
            ULL cntY = min(N, p[k] - 1) - p[k - 1] + 1; // y 的贡献
            ans = (ans + (__int128)cntX * cntY % MOD) % MOD;
        }
        cout << ans << endl;
    }
    return 0;
}

变量类型

在本题中,N 最大可达 (10^{18}),MMOD = 998244353 均在 32 位整型范围内。涉及的关键变量有:

  • cntX:满足条件的 \(x\) 的个数,最大不超过 \(N\),即 \(\le 10^{18}\)
  • cntY:固定位数的 \(y\) 的个数,最大也约为 \(9\times 10^{17}\)
  • ans:所有 \((x,y)\) 对数对 MOD 取模后的累加和,最终值在 \([0, \text{MOD})\) 内。

各变量的推荐类型

变量 推荐类型 理由
cntX unsigned long long 范围 \(0 \sim 2^{64}-1\approx 1.84\times 10^{19}\),足够容纳 \(10^{18}\)。无符号类型可避免负值,且移位/除法行为定义明确。
cntY unsigned long long 同上,且计算 min(N, p[k]-1) 时不会出现负数。
ans unsigned long longlong long 累加过程中多次取模,值始终小于 MOD\(<2^{31}\)),任何 64 位有符号/无符号类型均可。推荐 unsigned long long 保持一致性。
乘积 cntX * cntY 不能直接使用 64 位乘法 二者最大约 \(10^{18}\),乘积可达 \(10^{36}\),远超 64 位范围。必须使用 128 位乘法(GCC 的 __int128)暂存中间结果,再对 MOD 取模。
posted @ 2026-06-04 10:52  alice_ss  阅读(8)  评论(0)    收藏  举报
//雪花飘落效果