一.关于快速幂:
我们要想求a^b,也就是b个a相乘,我们可以设置ans = 1,然后for循环b次,用ans累成a得到最终答案ans,这样时间复杂度是O(b)
当b大于1e9,我们用上面的办法就不能在1s内求出结果了。
举个栗子2^11,我们仔细观察一下:
ans = 2 ^ 11
= 2✖️2✖️2✖️2✖️2✖️2✖️2✖️2✖️2✖️2✖️2
= 4✖️4✖️4✖️4✖️4✖️2
= 16✖️16✖️4✖️2
= 256✖️4✖️2
因此我们可以只求2,4,16,256中2,4,256组合得到2^11,而2,4,16,256可以根据平方递推得到,这样要想求得a ^ b的值时间复杂度只有O(log(b)),可以说是非常快了
代码如下:
ll quick(ll a, ll b) { //求a^b
ll ans = 1;
while (b) {
if (b & 1) ans *= a; //只有b为奇数时乘a,例如2^11时ans只累乘2,4,256
b >>= 1; //相当于b /= 2
a *= a; //就是上面所说的通过平方和递推,优化运算时间
}
return ans;
}
二. gcd扩展:
gcd几乎是我们刚入学接触的第一个递归了,大家想必已经熟记于心。
根据gcd(a, b) = gcd (b, a % b) (a > b且 b != 0) 公式,我们只需要知道递归的终止条件,就可以写出这个递归代码。
由于b != 0,所以当a % b == 0时不能继续递归。那么,当a % b == 0时,我们应该返回什么呢?谁才是a,b的最小公约数?
由于a % b == 0,因此a一定是b的倍数,也就说b一定是a的因子,又因为b的最大因子是b,因此a,b的最大公约数一定是b,根据gcd(a, b) = gcd(b, a % b),我们知道b也是最初始的a,b的最大公约数。
实现代码如下:
ll gcd (ll a, ll b) { //前提条件:a,b中不存在0
if (a < b) swap(a, b);
//若a,b中存在0,则可添加下一行代码:
//if(b == 0) return 0;
return a % b == 0? b: gcd(b, a % b);
}
好啦,我们说几个gcd的扩展定理:
(1).gcd (ka, kb) = k✖️gcd(a, b)
(2).lcm(ka, kb) = k ✖️lcm(a, b)
(3).lcm(s / a, s / b) = s / gcd(a, b)
有一些题目可通过这些扩展定理来少走很多弯路~
Over~
转载请注明出处!!!
如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢