1 条题解
-
0
自动搬运
来自洛谷,原作者为

阿丑
ArrTue搬运于
2025-08-24 21:32:08,当前版本为作者最后更新于2021-05-10 09:42:29,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题目大意:
-
求小于 并且满足“对其倒序数与其本身求和的结果每位数都是奇数”的数的数量。
-
题目中的例子:,其倒序数 就是 ,求和是,每位数都是奇数,满足条件。
而题目中的首位不能是 ,指的不仅是 不含前导零,还指不能有 这样的情况,因为 含前导零。
思路:
-
通过数学方法推导出公式。
-
因为位数 ,暴力高精即可。
下文将 记作 。
数学部分
假设 ,其中 表示 的位数,且有 ,、。
则 $n+reverse(n)=\overline{a_{f(n)}a_{f(n)-1}...a_2a_1}+\overline{a_1a_2...a_{f(n)-1}a_{f(n)}}$
$=\sum\limits^{f(n)}_{i=1}(a_i+a_{f(n)-i+1})×10^{i-1}$
为叙述方便,下列表格表示了 中的每一项。以 为例。
[7] [6] [5] [4] [3] [2] [1] 显然,第 项()和第 项()完全相同;并且 的第 位就等于第 项的个位和第 项的十位之和。接下来会借助这两点性质,将 的可能情况讨论出来。
温馨提示:请注意区分 的第 位和 [](即第 项)之间的区别。
首先,为使第 1 位(从右往左)为奇数,[1] 中必须为奇数。考虑到进位对其他位的影响,分为两种情况:大于 的奇数与小于 的奇数。
1、[1] 中是大于 的奇数
此时,[1]()可以取 、、、,不妨以 为例。
[7] [6] [5] [4] [3] [2] [1] 15 ? 15 这里,[6] 是不能进位的,否则会使 的第 7 位成为偶数。而由第 2 位为奇数知,[2] 内一定是偶数(因为 [1] 进位了)而 [2] 与 [6] 相同,故是不进位的偶数,即 、、、 或 。以 为例。
[7] [6] [5] [4] [3] [2] [1] 15 8 ? 8 15 同理,[5] 必须进位,而 [3] 必须是奇数,那么就是进位的奇数,可以发现与 [1]、[7] 符合的条件相同,即产生了循环。那么剩下的过程就可以递归求解。
但由于 的不同,情况也会不一样;由于四位(左右各两位)一循环,所以有四种情况。
1°
以 为例。
[4] [3] [2] [1] 15 8 15 此时第 3 位是偶数,不满足题设。
2°
以 为例。
[5] [4] [3] [2] [1] 15 8 11 8 15 此时 [3] 是奇数,而 [3] 为偶数,两者冲突。
3°
以 为例。
[6] [5] [4] [3] [2] [1] 15 8 11 8 15 此时第 4 位是偶数(),不满足题设。
4°
以 为例。
[7] [6] [5] [4] [3] [2] [1] 15 8 11 6 11 8 15 此时是可以满足题设的。(与上表对应的 为 )
而通过
枚举数学方法得知,[1] 与 [7] 对应的 与 一共有 种情况,[4] 对应的 有 种情况(请自行推导 orz)。而 [6] 与 [2] 有 种情况,[5] 与 [3] 有 种情况。而在上文推导过,一次“循环”是两位,由乘法原理知一次“循环”是 种情况。故一共有 种情况。注意,一定在 时才成立。
2、[1] 中是小于 的奇数
此时,[1] 可以取 、、、、,不妨以 为例。
[7] [6] [5] [4] [3] [2] [1] 7 ? 7 [6] 不能进位,否则会使第 7 位成为偶数。而由第 2 位为奇数知,[2] 内一定是奇数。故是不进位的奇数,与 [1]、[7] 符合条件相同。即再次产生了循环。
当然, 不同时情况也不一样。当 时,最中间一位会是奇数。仍以 作为例子,即 [4] 为奇数;而 [4] 为偶数,矛盾。
当 时,以 为例:
[4] [3] [2] [1] 5 3 5 类似地,可以推出 [1] 与 [4] 对应的 、 有 种情况,而 [3]、[2] 对应的 、 有 种情况,即一“循环”是 种情况。一共有 种情况。
高精部分
由以上的数学推论,可以知道我们只需要写出高精乘低精、高精加高精(统计答案)即可。具体写法可以参考代码部分。
#include<bits/stdc++.h> using namespace std; const int N=400+20; struct BigInt { int a[N], len; inline void carry() { //进位,顺便更新 len for(int i=0; i<len; i++) { a[i+1]+=a[i]/10, a[i]%=10; if(a[len]) ++len; //更新 len } } BigInt operator = (int i2) { //将低精赋值给高精 for(int i=1; i<=N-3; i++) a[i]=0; //清零 len=1, a[0]=i2, carry(); } BigInt operator * (int i2) { //高精乘低精 BigInt ret=*this; for(int i=0; i<ret.len; i++) ret.a[i]*=i2; ret.carry(); return ret; } BigInt operator + (BigInt b2) { //高精加高精 BigInt ret=*this; ret.len=max(ret.len, b2.len); for(int i=0; i<ret.len; i++) ret.a[i]+=b2.a[i]; ret.carry(); return ret; } inline void output() { //输出 for(int i=len-1; i>=0; i--) printf("%d", a[i]); } } ans; int x; int main() { ans=0; scanf("%d", &x); for(int i=1; i<=x; i++) { //从 1 到 x 都要计算 if(i%2==0) { //f(n)%2==0 BigInt dl; dl=20; for(int t=1; t<=(i-2)/2; t++) dl=dl*30; //(i-2)/2 次幂 ans=ans+dl; } else if(i%4==3) { //f(n)%4==3 BigInt dl; dl=20*5; for(int t=1; t<=(i-3)/4; t++) dl=dl*(20*25); //(i-3)/4 次幂 ans=ans+dl; } } ans.output(); return 0; }update 21.6.8:将代码尽量改成了初学者能够接受的写法,并更正了笔误。
-
- 1
信息
- ID
- 907
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者