题目 | digitnum
AtCoder Beginner Contest 238
C - digitnum
https://atcoder.jp/contests/abc238/tasks/abc238_c
Time Limit: 2 sec / Memory Limit: 1024 MB
Score : $300$ points
Problem Statement
Given an integer $N$, solve the following problem.
Let $f(x)=$ (The number of positive integers at most $x$ with the same number of digits as $x$).
Find $f(1)+f(2)+\dots+f(N)$ modulo $998244353$.
Constraints
- $N$ is an integer.
- $1 \le N < 10^{18}$
Input
Input is given from Standard Input in the following format:
$N$
Output
Print the answer as an integer.
Sample Input 1
16
Sample Output 1
73
For a positive integer $x$ between $1$ and $9$, the positive integers at most $x$ with the same number of digits as $x$ are $1,2,\dots,x$.
- Thus, we have $f(1)=1,f(2)=2,...,f(9)=9$.
For a positive integer $x$ between $10$ and $16$, the positive integers at most $x$ with the same number of digits as $x$ are $10,11,\dots,x$.
- Thus, we have $f(10)=1,f(11)=2,...,f(16)=7$.
Sample Input 2
238
Sample Output 2
13870
Sample Input 3
999999999999999999
Sample Output 3
762062362
Be sure to find the sum modulo $998244353$.
我的笔记
这道题很明显是一个逆元题,并没有什么难度,只不过当时完全忘记了除法逆元这回事,于是较大数据全部 WA
除法逆元:
由费马小定理可推出:$\frac{1}{a} \% m = a^{m-2} \% m$ ,其中m为素数。
那么,$\frac{b}{a} \% m$ 就可以变成 $b\times a^{m-2} \% m$
如果 $m$ 太大,可以使用快速幂。
因为本题只用 /2 需要逆元,因此直接把 2 的逆元求出来然后代入就行了,不需要每次都求一边。写个程序算出来为 499122177
解决完逆元问题后我仍然没有得出正确答案,折腾了半天发现中途乘法溢出了 long long 范围。比如 long long ans = ((1 + N - pow_10(num_digit - 1) + 1) % MOD * (N - pow_10(num_digit - 1) + 1) % MOD * 499122177) % MOD
,三个数都是 1e9 级别的,乘起来肯定溢出了。因此得每乘一次就取一次模。
源码
#include <bits/stdc++.h>
#define MOD 998244353
#define INV_2 499122177
using namespace std;
long long pow_10(int x)
{
long long ans = 1;
for (int i = 0; i < x; i++)
ans *= 10;
return ans;
}
int main(void)
{
long long N;
cin >> N;
long long t = N;
int num_digit = 0;
while (t)
{
t /= 10;
num_digit++;
}
long long x = (N - pow_10(num_digit - 1) + 1) % MOD;
long long ans = x;
ans *= x + 1;
ans %= MOD;
ans *= INV_2;
ans %= MOD;
for (int i = num_digit - 1; i > 0; i--)
{
long long y = (pow_10(i) - pow_10(i - 1)) % MOD;
long long tmp = y;
tmp *= y + 1;
tmp %= MOD;
tmp *= INV_2;
tmp %= MOD;
ans += tmp;
ans %= MOD;
}
cout << ans << endl;
return 0;
}
本文采用 CC BY-SA 4.0 许可,本文 Markdown 源码:Haotian-BiJi