题解系列003 | 洛谷CF869B 【The Eternal Immortality】

原题传送门:The Eternal Immortality

读完题目,我们可以发现这题实质上就是让我们求两个数的阶乘的商模10的余数。但题目中给的数据是 0 ≤ a ≤ b ≤ 1 0 18 0\leq a\leq b\leq 10^{18} 0≤a≤b≤1018,显然直接使用阶乘会直接炸掉(用python也会TLE),因此这种方法直接否决。

但是,经过一番观察,我们发现这里 a ! a! a!和 b ! ( a ≤ b ) b!(a\leq b) b!(a≤b)有很大一部分是“重叠”的,即:

b ! a ! = b ⋅ ( b − 1 ) ⋅ … ⋅ 1 a ⋅ ( a − 1 ) ⋅ … ⋅ 1 = b ⋅ ( b − 1 ) ⋅ … ⋅ ( a + 1 ) \dfrac{b!}{a!}=\dfrac{b\cdot (b-1)\cdot\ldots\cdot1}{a\cdot(a-1)\cdot\ldots\cdot1}=b\cdot(b-1)\cdot\ldots\cdot(a+1) a!b!​=a⋅(a−1)⋅…⋅1b⋅(b−1)⋅…⋅1​=b⋅(b−1)⋅…⋅(a+1)

因此可以利用这个方法大大减缓计算量。

但这样还是不行的。注意在这种情况下,我们并没有对差距特别大的数做出实际的优化。比如说我们输入 1 1 1和 100000000000 100000000000 100000000000,用上面的公式还是需要将 100000000000 100000000000 100000000000个数相乘,没有减少计算量。因此还需要发掘其它的性质。

这里我们注意到 m o d    10 \mod 10 mod10 计算的优点:碰到一个5和一个2个位基本就是0了。进一步看,也即当两个数满足 b − a > 5 b-a>5 b−a>5时, b ! a ! \dfrac{b!}{a!} a!b!​的末位一定是0(这里用到了“任何连续n个数的乘积一定被n整除”这个性质)

这样计算就大大优化了。比如说我们输入 1 1 1和 100000000000 100000000000 100000000000,根据上面的算法,无需计算就可以直接得出答案是0。因此可以看到,用适当的数学知识可以减轻计算机的工作量!

上代码:

#include <iostream>
using namespace std;

int main()
{
	long long a, b, al, bl;
	int ans = 1;
	cin >> a >> b;
	if (b - a > 5)
		cout << 0;
	else
	{
		for (long long i = a + 1; i <= b; i++)
		{
			ans = (ans % 10) * (i % 10);
		}
		cout << ans % 10;
	}

	return 0;
}

(留个赞再走吧

欢迎大家关注我的博客!

我的洛谷账号:这是我

我的洛谷团队:这是我的团队

欢迎大家关注我,并加入我的团队哦^ _ ^

上一篇:js css3 拖拽旋转


下一篇:javascript – 在jQuery / JS中旋转时触发事件的旋转旋钮