题解:洛谷 AT_abc357_d 88888888
【题目来源】
洛谷:AT_abc357_d [ABC357D] 88888888 - 洛谷(luogu.com.cn)
【题目描述】
For a positive integer \(N\), let \(V_N\) be the integer formed by concatenating \(N\) exactly \(N\) times.
对于一个正整数 \(N\),令 \(V_N\) 为将 \(N\) 重复连接 \(N\) 次形成的整数。
More precisely, consider \(N\) as a string, concatenate \(N\) copies of it, and treat the result as an integer to get \(V_N\).
更准确地说,将 \(N\) 视为字符串,连接 \(N\) 个它的副本,并将结果视为整数,得到 \(V_N\)。
For example, \(V_3=333\) and \(V_{10}=10101010101010101010\).
例如,\(V_3 = 333\),\(V_{10} = 10101010101010101010\)。
Find the remainder when \(V_N\) is divided by \(998244353\).
求 \(V_N\) 除以 \(998244353\) 的余数。
【输入】
The input is given from Standard Input in the following format:
N
【输出】
Print the remainder when \(V_N\) is divided by \(998244353\).
【输入样例】
5
【输出样例】
55555
【核心思想】
-
问题分析:给定正整数 \(N\),构造 \(V_N\) 为将 \(N\) 作为字符串重复连接 \(N\) 次所形成的整数,求 \(V_N \bmod 998244353\)。由于 \(N\) 可达 \(10^{18}\),直接构造 \(V_N\) 不可行,需通过数学公式将字符串拼接转化为数值运算,利用等比数列求和与模运算高效求解。
-
算法选择:
- 等比数列求和公式:将 \(N\) 次拼接表示为 \(V_N = N \cdot \sum_{i=0}^{N-1} 10^{i \cdot l}\),其中 \(l\) 为 \(N\) 的十进制位数,转化为等比数列求和问题
- 快速幂(Binary Exponentiation):高效计算 \(10^k \bmod 998244353\),时间复杂度 \(O(\log k)\)
- 费马小定理求模反元素:利用 \(998244353\) 为质数,通过 \(a^{-1} \equiv a^{p-2} \pmod p\) 计算 \((10^l - 1)^{-1} \bmod 998244353\)
- 欧拉定理降幂:在指数运算中利用 \(\phi(998244353) = 998244352\) 对指数取模,避免大数运算
-
关键步骤:
- 计算位数:\(l = \text{getlen}(N)\),即 \(N\) 的十进制位数
- 建立数学模型:
- 每次拼接相当于将当前结果左移 \(l\) 位(乘以 \(10^l\))再加上 \(N\)
- \(V_N = N + N \cdot 10^l + N \cdot 10^{2l} + \cdots + N \cdot 10^{(N-1)l} = N \cdot \frac{10^{N \cdot l} - 1}{10^l - 1}\)
- 分子计算:\(c_1 = (10^{N \cdot l} - 1) \bmod 998244353\),其中指数 \(N \cdot l\) 需先对 \(998244352\) 取模(欧拉定理降幂)
- 分母求逆:\(c_2 = (10^l - 1)^{-1} \bmod 998244353 = (10^l - 1)^{998244351} \bmod 998244353\)
- 合成结果:\(\text{res} = N \bmod 998244353 \cdot c_1 \bmod 998244353 \cdot c_2 \bmod 998244353\)
-
时间/空间复杂度:
- 时间复杂度:\(O(\log N + \log 998244353)\),其中 \(O(\log N)\) 用于计算位数和快速幂中的指数处理,\(O(\log 998244353)\) 用于两次快速幂运算(分子和模反元素)
- 空间复杂度:\(O(1)\),仅使用常数个变量存储中间结果
-
数论与等比数列的核心思想:
- 字符串拼接的代数化:将重复拼接操作转化为等比数列求和,避免直接处理超大整数
- 模运算下的除法转乘法:在模质数域中,除法等价于乘以模反元素,确保所有运算在模意义下封闭
- 指数降幂技巧:利用欧拉定理 \(a^b \equiv a^{b \bmod \phi(p)} \pmod p\)(当 \(a\) 与 \(p\) 互质时),将超大指数 \(N \cdot l\) 降至可计算范围
- 快速幂的高效性:通过二进制分解将幂运算从 \(O(n)\) 优化到 \(O(\log n)\),是处理大数模运算的基础工具
- 适用于大数构造、重复模式数值化、模意义下的级数求和问题
【算法标签】
普及 #欧拉定理
【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long // 定义宏,将 int 替换为 long long,方便处理大整数
const int mod = 998244353; // 定义常量 mod,表示模数
int n; // 定义变量 n,表示输入的数
// 快速幂函数,计算 a^b % p
int qmi(int a, int b, int p)
{
int res = 1; // 初始化结果为 1
while (b) // 当 b 不为 0 时
{
if (b & 1) res = res * a % p; // 如果 b 的最低位为 1,更新结果
a = a * a % p; // 更新 a
b >>= 1; // 右移一位
}
return res; // 返回结果
}
// 计算数字 x 的位数
int getlen(int x)
{
int res = 0; // 初始化结果为 0
while (x) // 当 x 不为 0 时
{
res++; // 位数加 1
x /= 10; // 去掉最后一位
}
return res; // 返回位数
}
signed main()
{
cin >> n; // 输入数字 n
int l = getlen(n); // 计算数字 n 的位数 l
// 计算 c1 = (10^(n * l) - 1) % mod
int c1 = qmi(10, n % (mod - 1) * l % (mod - 1), mod) - 1;
// 计算 c2 = (10^l - 1)^(-1) % mod
int c2 = qmi(10, l, mod) - 1;
c2 = qmi(c2, mod - 2, mod); // 计算模反元素
// 计算最终结果 res = n * c1 * c2 % mod
int res = n % mod * c1 % mod * c2 % mod;
cout << res << endl; // 输出结果
return 0;
}
【运行结果】
5
55555
浙公网安备 33010602011771号