2022.3.22 17:05 洛谷P1009

开头:

这题一开始我以为只是普通的循环计算题,后来研究了很久都没有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) 高精度算法本质上是模拟数字的运算。

这个概念非常重要!!

你要先理解“模拟数字”的本质,不然很难理解这道题洛谷题解里面写的代码的含义(我就这样)

对于像我一样之前没有了解到“高精度”的菜鸟来说

建议先把“高精度”的理念搞懂,再做题

推荐食用:

高精度减法的解析:

P2142 高精度减法_哔哩哔哩_bilibili

本题的讲解:(我觉得讲得挺不错的,虽然说第一次看我也没看懂)

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)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值