快速幂的目的是做到 快速求幂
举个栗子!!!
我们要计算a^b -------朴素算法是把a连乘b次
时间复杂度是O(n)级别,而快速幂能做到O(logn)
好 继续看---- 求a^b:
其实b是可以拆成二进制的,该二进制数第i位的权(值)为2^(i-1),
比如说b==11时
11的二进制是1011,
- 11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1
之前提到了 朴素算法是把a连乘11次
而现在我们就可以有一个很棒的转化↓
其实也就是:↓
- 原来需要算11次
- 现在只需要算3次
- 省时间啊!!耐思!
那么问题就来了↓
这三项…
好像…
不怎么不好求…???
来看一下代码吧!
long long zzpow(long long x, long long y)
//指数爆炸!你可以用longlong 或者用mod也可以
{
int ret = 1, base = x;
while (y != 0) //y不等于0
//当然你也可以写while(y)
{
if (y & 1 != 0)
//y&1是位运算,等同于y%2!=0
//也就是y是奇数
ret *= base;
//这一行的作用会在下面讲
base *= base;
//目的是累乘
//base * base == base ^ 2
//下一步再去乘 base^2 * base^2 == base^4
//base^4 * base^4 == base^8
//base^8 * base^8 == base^16
//base16 * base16 == base^32
//所以这一步 base *= base就达到了 指数是2^i的转换!
y >>= 1;
//移动一位,二进制里面的,等同于 y/=2
}
return ret;
}
讲到二进制 一般都会想到这两个小别致 大宝贝
>>和&(位运算の使用)
1. >>运算 就是二进制去掉最后一位
2. &运算通常用于二进制取位操作,也可以用于判断奇数偶数
来再举个栗子
- 一个数 & 1 的结果就是取二进制的最末位。
- y&1 == 0 为偶,y&1 == 1为奇。
再聊聊这个
二进制从右向左算
就以y==11来看 y=>1011
乘出来的顺序是从左向右
也就是 a^ (2^0) * a^ ( 2 ^ 1 ) * a ^ (2^3)
a ^ 11 = a^1 * a^2 * a^8
以及 最后的结果ans 应该是还要再乘一个刚开始的ans
总代码:
/*
&运算,就是表示和&&有点类似,但是&&是两边的条件成立就成立
&也是这样,n&1表示如果两边的二进制的最后一位都为1,那么就成立,否则就不成立
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define zz 200907
typedef long long ll;
ll a,b,c,k,ans;
ll power(ll x,ll y)
{
ll ret=1;
while(y) //while(y!=0)
{
if(y&1) ret=(ret*x)%zz; //y&1是位运算,等同于y%2!=0
// (ret*x)%z就是取mod
y>>=1;//移动一位,二进制里面的,等同于 y/=2
x=x*x%zz; //平方求mod
//可以这样是因为 次方求mod,可以边乘边mod,(mod就是求余数)
}
return ret;
}
void solve()
{
int d;
scanf("%lld%lld%lld%lld",&a,&b,&c,&k);
if(c-b==b-a) //表示等差数列
{
d=(b-a)%zz; //求公差
ans=(a+(k-1)%zz*d)%zz; //首项+要求的前一项*公差,
//因为要求mod,所以要再里面求的时候mod一次,外面mod一次,就是边乘边mod
}
else //等比数列
{
d=(b/a)%zz;//求公比
ans=a%zz*power(d,k-1)%zz;//通过不断用公差进行平方的mod运算,求出答案
}
printf("%lld\n",ans);
}
int main()
{
int t; scanf("%d",&t);
while(t--)
{
solve();//也可以直接将solve函数中的判断拉到这里
/*
scanf("%lld%lld%lld%lld",&a,&b,&c,&k);
if(c-b==b-a)
{
ans=(a+(k-1)%z*(b-a)%z)%z;
}
else
{
ans=a%z*power((b/a)%z,k-1)%z;
}
printf("%lld\n",ans)
*/
}
return 0;
}
晚上来发关于幂运算的题目吧ouo