2nd.解题报告(有关快速幂)2019.12.16
题目
此题来自令人自闭の18级蓝桥校选😑
解题思路(其实是坎坷的心路历程)
让我们先来思考一下题目什么意思
在学过小学一年级之后我们可以理解到这个题目
大概就是说汤达人是个菜狗然后LJL是个大佬
大概就是说n天,第一天能跳1米远,第二天能跳1×m米远,第三天能跳1×m×m米远,第四天能跳1×m×m×m米远,第n天能跳m(n-1)米远。
再粗暴一点的意思就是输入两个数n与m,求m(n-1)次方。
听起来很简单是不是,只要一个循环累乘就能过对不对!!!让砸们试一下!!!!!
第一次尝试
快乐的出现了两个答案正确和三个答案错误。
出现了答案正确就说明你离正确答案不远了——鲁迅
emmmmmmm让我们康康忽略了啥!!!
没错就是它,有些题目为了保证可以得到唯一的答案又不超过数据范围限制需要做的一些处理
于是我们就有了以下的代码
for (long long i = 0; i < n-1; i++) {
sum = sum * m%10007;
}
第二次尝试
这次应该可以了吧,让砸们再试一下!!!
????????WTF????????
超时是什么鬼????????????
确实自己调试的时候会发现时间运行的时间有点长,好的吧让我们应用小学二年级的知识再来分析一下
普通的计算机1s循环的极限是1e8次左右
题目循环最大次数
实际最坏情况代码的运行时间(1600+ms)
本题的时间限制
事实证明,蓝桥17级出题组是有多毒瘤(虽然18级好不到哪去)
事实也证明,这题用O(n)的算法是无法AC的。
全剧终
为了秉承社会主义接班人的优良传统
还是百度了一下“C语言怎么快速进行幂运算”,得到了一个名叫【快速幂】的算法
顾名思义,快速幂就是快速算底数的n次幂。其时间复杂度为 O(log₂N), 与朴素的O(N)相比效率有了极大的提高。——《快速幂》
快速幂的大概思路
先说一下它怎么做
假设你要求的为m11
首先任何一个数都可以从一个数变为二进制加法形式如11=23×1+22×0+21×1+20×1
则m11=m23×1+22×0+21×1+20×1
即m11=m23×m21×m20,11的二进制为1011,在这里我们可以发现指数二进制位的1或者0直接决定了那一位的m2n会不会被乘进结果,这是一个非常巧妙的做法,再次感叹一下数学之美
这里还要通过小学三年级的知识推导一个下面会用到的公式m2(n+1)=m2n×m2n
让我们写一下Quickpowの流程图!!!!
我们再写个函数的代码(考虑取模)
long long Quickpow(int m,int n){
long long r=1;
while(n!=0){
if(n%2) r=r*m%10007;//条件是短除法判断二进制此位需不需要乘进去
m=m*m%10007;//用到上面推导的公式,不管是否乘入结果每次都需要乘
n/=2;
}
return r;
}
到这里我们就会发现如果要计算m11用原来传统的办法需要循环11次,而用快速幂只需要循环4次(实际的结果只乘了3次)
且指数越大时,快速幂的效率提升就越明显。
涉及到二进制,我们还可以考虑一下位运算加点小优化,但在这里就不多赘述了(为了赶作业)
结尾
博客园这个东西,从写了开学第一篇作业之后,就再也没碰过。
这可以侧面说明自己这一个学期来其实并没有学到什么很多新的东西,过的过于安逸了。
本来想把快速幂写成大家都能看懂的博客。
最后发现自己都有些地方都不是很清楚(比如快速幂里面的取模为什么这么写),更不用想和别人说清楚了(甚至可能有些地方会误导人),但为了完成作业还是有些马虎地写完了。
归根到底还是能力不足昂。
如果有人认真看完还不能完全理解的请务必找我一起探讨qaqqq
一知半解还请评论区大佬补充。
End.