开头:
这题一开始我以为只是普通的循环计算题,后来研究了很久都没有100,于是没法就去看了看题解,我才了解到这是一道需要“高精度”计算的题,但我对“高精度”完全不了解,甚至是第一次听到。感谢题解区大佬SingularWind的科普。
高精度算法科普:(加粗的为原大佬题解部分,剩下的为我自己的理解)
(1) 有时有的数会太大,甚至超过了long long的范围(263−1≈9×1018)
(
一个long long 类型占8个字节,其中 一个字节 8个(比特)位,即 long long类型 有8X8=64 个二进制位 来实现一个数字
long long 的取值为:-2^63 到 2^63 -1
问题一:为什么是2^?为什么不是3^?
回答一:
这个我觉得可以理解成 “有多少种变化”
对于每个二进制位,只有0和1两个数字,不能为2
因为二进制嘛,如果为2的话这位就变成零,“下一位”就+1
如果“下一位”本来是1,+1之后变成2,那这个“下一位”就变0,“下下一位”就+1............如此反复
然后为什么是2^(^是多少方的意思)?为什么不是2*(乘)?
这个我觉得拿例子说明比较好懂一点(其实我思来想去也想不到怎么说好,干脆拿例子了)
例一:1个(比特)位有几种变化? 2种
00 01 共2种,即2 ^ 1 = 2(种)
例二:2个(比特)位有几种变化? 4种
00 01 10 11 共4种,即2 ^ 1 = 4(种)
如此类推:64个(比特)位有几种变化? 2 ^ 64 = ????(种)
问题二:为什么是^63?不是说有64位,一共 2 ^ 64 种变化的?
回答二:
0000..(反正一共64位)...0000,从右到左为个位、百位、千位.......
开头的第一位是“符号位”,如果是0表示是正数,如果是1表示是负数
什么?那如果是2呢?
为2的话 这位 就变0,下一位更大的就进1,可是符号位在最左边,也可以说没有下一位了,再进1不就寄了?你的报错就这么来的。
所以变化是2 ^ 64,但真正的实际取值要砍掉最左边的符号位,应该是2 ^ 63
问题三:为什么左范围是 -2^63 ,右范围却是 2^63 -1 ?
回答三:
首先,0是不包含在左范围和右范围里面的。就像[-4,4]有9个数,0以及正负的各四个,共9个数
本来除去最左边的“符号位”,只剩下63位
0,即 0000...(反正一共64位)...0000 不在左右范围内,所以左右范围都要 “ -1 ”,为 2 ^ 63 -1
但左范围相比右范围,有一个特殊的: 1000...(反正一共64位)...0000 , 这个是 -0 ?
非也,这个特别的被特别定义为“xxx”(xxx= 2 ^ 63运算的结果,就是2的63次方最后算出来的数)
所以左范围比右范围多一个数,左范围 2 ^ 63 -1 + 1 = 2 ^ 63
总结:左范围比右范围多一个数,为 -2^63
右范围为 2^63 -1
)
(2) 此时需要用字符串(string型或char型数组)来存储数字,运算时需要特殊的算法进行运算,称为高精度算法。
(
数组的容量上限只取决于 你一开始定义的大小,你可以在数组定义的[ ]内塞一个超级大的数
所以理论上是无限大的
)
(3) 高精度算法本质上是模拟数字的运算。
(
这个概念非常重要!!
你要先理解“模拟数字”的本质,不然很难理解这道题洛谷题解里面写的代码的含义(我就这样)
对于像我一样之前没有了解到“高精度”的菜鸟来说
建议先把“高精度”的理念搞懂,再做题
推荐食用:
高精度减法的解析:
本题的讲解:(我觉得讲得挺不错的,虽然说第一次看我也没看懂)
P1009 [NOIP1998 普及组] 阶乘之和_哔哩哔哩_bilibili
(如果直接看的话可能很难看懂,建议先看高精度减法,然后对“高精度”有个大概的了解后再搞)
)
(以上科普部分引自SingularWind大佬的题解内容,扩展补充由我添加)
我的高精度了解:
(大概就这样,凑合着看吧)
C/C++:(100分) (感谢罗老师教会我了)
#include <iostream>
using namespace std;
#define Max 10000
int a[Max] = { 0 };
int b[Max] = { 0 };
void cheng(int* a, int n)
{
int jin = 0;
for (int i = 1; i <= Max; i++)
{
a[i] = a[i] * n + jin;
jin = a[i] / 10;
a[i] = a[i] % 10;
}
}
void jia(int* a, int* b)
{
int jin = 0;
for (int i = 1; i <= Max; i++)
{
b[i] = b[i] + a[i] + jin;
jin = b[i] / 10;
b[i] = b[i] % 10;
}
}
int main()
{
int n = 0; //这个不能搞全局变量,不然会出问题
cin >> n;
a[1] = 1; //如果输入的n = 1就直接输出1
for (int i = 1; i <= n; i++) //计算阶乘
{
cheng(a, i);
jia(a, b);
}
int i = Max;
bool ab = 0;
while (--i >= 1)
{
while (b[i] != 0 || ab)
{
printf("%d", b[i]);
ab = 1;
break;
}
}
return 0;
}
python: (100分)
这里python写法的思路是利用了 n! = n x (n - 1)!
n = int(input(""))
jiecheng = 1;
sum = 1;
i = 2;
if n == 1:
print("1")
while i <= n:
jiecheng *= i
i += 1
sum += jiecheng
print(sum)