专栏文章
题解:P3922 中学数学题
P3922题解参与者 6已保存评论 10
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 10 条
- 当前快照
- 1 份
- 快照标识符
- @miojiuuv
- 此快照首次捕获于
- 2025/12/02 20:14 3 个月前
- 此快照最后确认于
- 2025/12/02 20:14 3 个月前
P3922 中学数学题 题解
题意还是很明了的,一看就明白,不再赘述。
其实笔者看到这题就想暴力。
但是在看到难度和数据范围时不舍地捏碎了我的暴力梦。
解密输入后发现 最大是 ,根据通项公式,得到数列中可能的最大值为 果断放弃暴力。
极大的数据启示我们寻找规律。
Part 1:规律:
先贴上找规律用的代码:
code1:
CPP#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
// 乘2
string multwo(const std::string& num) {
string result;
int carry = 0;
for (int i = num.size() - 1; i >= 0; --i) {
int digit = (num[i] - '0') * 2 + carry;
result.push_back(digit % 10 + '0');
carry = digit / 10;
}
// 处理进位
while (carry > 0) {
result.push_back(carry % 10 + '0');
carry /= 10;
}
// 反转结果字符串以获得正确顺序
reverse(result.begin(), result.end());
return result;
}
int main() {
string current = "1";
// 计算并输出2的1到10000次幂
for (int i = 1; i <= 10000; ++i) {
// 输出当前幂次和结果
cout << "2^" << i << " = " << current << std::endl;
// 计算下一个幂次
current = multwo(current);
}
return 0;
}
使用这段代码输出 的 到 次幂,开始找规律。
为了方便讲解,我把前 行输出粘贴到下面:
CPP2^1 = 1
2^2 = 2
2^3 = 4
2^4 = 8
2^5 = 16
2^6 = 32
2^7 = 64
2^8 = 128
2^9 = 256
2^10 = 512
2^11 = 1024
2^12 = 2048
2^13 = 4096
2^14 = 8192
2^15 = 16384
2^16 = 32768
2^17 = 65536
2^18 = 131072
2^19 = 262144
2^20 = 524288
2^21 = 1048576
2^22 = 2097152
2^23 = 4194304
2^24 = 8388608
2^25 = 16777216
2^26 = 33554432
2^27 = 67108864
2^28 = 134217728
2^29 = 268435456
2^30 = 536870912
2^31 = 1073741824
2^32 = 2147483648
2^33 = 4294967296
2^34 = 8589934592
2^35 = 17179869184
2^36 = 34359738368
2^37 = 68719476736
2^38 = 137438953472
2^39 = 274877906944
2^40 = 549755813888
2^41 = 1099511627776
2^42 = 2199023255552
2^43 = 4398046511104
2^44 = 8796093022208
2^45 = 17592186044416
2^46 = 35184372088832
2^47 = 70368744177664
2^48 = 140737488355328
2^49 = 281474976710656
2^50 = 562949953421312
统计了开头各数字出现次数后,发现以 为开头的项较少,考虑通过其他开头数字出现的规律来求解。
观察到以 为开头的数字有很多,不妨考虑以 为开头的数字。
将开头数字单独摘出:
发现 好像在循环。
继续往下找,又发现两种以 开头,结尾的序列:
按字典序排列后:
奇怪的事情发生了。
我们暂且称上面几种序列为“循环段”,用 表示,值为原数列中 的最高位的值。
顺便定义由 得到 的函数:
代入 , 得:
(注:此处 均为以十为底的对数,即 ,考虑可读性不在定义式中加入。)
发现:
段长为 时,段中出现一个 。段长为 时,段中不出现 。
在笔者往下看了几百行数字后,更确信此结论的正确性。
Part 2:证明:
命题:循环段长度为 , 且仅有如上 种:
因为原数列中每项都等于前一项 。所以每个数位都应 前一位 (竖式乘法计算步骤)。若段长为 :则 对应的项的前两位应为此循环段中第一个 的数。根据循环段定义 (首尾为 ):则此循环段的 一定不是 ,即原数列这一项开头不是 。考虑由 得到 的情况:每次 ,对吧?又因为第一位为 , 考虑进位最多的情况:如 ~ :CPP2^75 = 18889465931478580854784 2^76 = 37778931862957161709568 2^77 = 75557863725914323419136 2^78 = 15115727451828646838272 2^79 = 302231454903657293676544发现每次进位都是先 后 。不进位仅 。所以:的值为 ,而 无论 取何值,经过扩展后的 值只有一个:。根据循环段的定义,段长最大为 。又因为 是循环段中第一个可能出现 的单位,所以段长最短为 。根据 到 的值及进位规律,易得到下面这张表:上图中红边代表不进位且得到的 ,也可理解为 。蓝边代表进位且得到的 , 即 。绿边代表得到的 ,也即 。由上文定义可知:绿边后必连接 ,当遇到绿边时,说明循环段结束。图中共有 条绿边,说明前文定义的循环段形式有限,数量为 种。顺着红蓝边查找路径,将路径经过的点按顺序排列后发现:所以,循环段的长度为 ,且是上文列出的 种情况之一。证毕。
这部分是给和笔者一样的蒟蒻们理清思路而写的。
(俺一下午才明白),有错误欢迎指出!
Part 3: 题目解法:
我们已经将这个等比数列划分成了几个循环段的拼接。
因为循环段开头结尾都为 ,不好处理,舍弃最后一个 ,记作 :
观察到对于每一个 ,当长度为 时,其中必然包含 个 。
不妨设序列的前 项中有 个循环段满足此段项数为 ,即上两种。
可以发现, 若发生了进位,那么 的位数将会多 。
找到满足 且 的最大的 。
设 2^k' 共有 位。
考虑 时共发生了几次进位即 。
观察到循环段与进位的关系:
不进位进位进位进位进位
相加后发现进位次数就等于循环段的个数。
就可以求出段长为 的段数的个数:
根据项数列方程可得:
解得:
因为 是 在十进制下的位数,所以:
就得到答案了。
纪念我的第一道紫题!
和我的第一道紫题题解!
相关推荐
评论
共 10 条评论,欢迎与作者交流。
正在加载评论...
