原题传送门: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;
}
(留个赞再走吧