快速幂和快速乘
题目 a^b 多组输入a,b 求a^b的个位数
快速幂:
#include<stdio.h>
int ksm(long long a,long long b,long long c)
{
int ans=1;
while(b)
{
if(b&1)
{
ans=(ans*a)%c;
}
a=(a*a)%c;
b=b/2;
}
return ans;
}
int main()
{
long long n,m;
while(~scanf("%lld %lld",&n,&m))
printf("%lld\n",ksm(n,m,10));
return 0;
}
当a,b很大的时候 在10^9时,用常规的方法就容易超时
所以就优化
首先n^x * x^y = n^(x+y),这个是显然的吧……
那么由此可以推出
n^m = n^x1 * n^x2 * ... * n^xi ,其中 x1 + x2 + ... + xi = m
那么,我们应该找到一种最优的方式把m分解,然后用可以很容易计算出来的n^x值相乘,就可以得到n^m的答案。
那么由此可以推出
n^m = n^x1 * n^x2 * ... * n^xi ,其中 x1 + x2 + ... + xi = m
那么,我们应该找到一种最优的方式把m分解,然后用可以很容易计算出来的n^x值相乘,就可以得到n^m的答案。
什么样的n^x算起来最快呢?
x = 1 , n^x = n
x = 2 , n^x = n^2
x = 4 , n^x = n^4 = (n^2)^2
x = 8 , n^x = n^8 = (n^4)^2
....
x = 1 , n^x = n
x = 2 , n^x = n^2
x = 4 , n^x = n^4 = (n^2)^2
x = 8 , n^x = n^8 = (n^4)^2
....
然后,我们知道任何一个数都可以轻松用1,2,4,8,16...的和表示出来,即,把这个数转为二进制即可。
那么对于任意一个n^m,我们就可以在O(log m)的时间内完成了。
For example: 求2^13
2^13 = 2^1 * 2^4 * 2^8
就可以了……
那么对于任意一个n^m,我们就可以在O(log m)的时间内完成了。
For example: 求2^13
2^13 = 2^1 * 2^4 * 2^8
就可以了……
快速乘
#include<stdio.h>
long long ksm(long long,long long,long long);
long long ksc(long long,long long,long long);
int main()
{
long long n,m;
while(~scanf("%lld%lld",&n,&m))
printf("%lld\n",ksm(n,m,10));
return 0;
}
long long ksm(long long a,long long b,long long c)
{
long long ans=1;
while(b)
{
if(b%2)
ans=ksc(ans,a,10)%c;
a=(a*a)%c;
b/=2;
}
return ans;
}
long long ksc(long long a,long long b,long long c)
{
long long ans=0;
while(b)
{
if(b%2)
ans=(ans+a)%c;
a=(a+a)%c;
b/=2;
}
return ans;
}
当a,b<=10^18时 快速幂也不能解决了 所以引入快速乘
沿用之前的方法,但是注意这里的模数是10^18
之前10^9*10^9 long long 可以存下
考虑到幂次可以转换成连续乘
连续乘可以转换成连续加
a^4 = a*a*a*a
a*a =(a+a+a.....a)
注意到两个10^18的数相加是可以的
同样我们得到一个快速乘
比如计算出a,2a,4a,8a,16a
每次乘二,不会爆