快速幂
什么是快速幂呢?
试想,如果你想计算a^b,你该怎么做呢?
我们只需b个a相乘即可,但是这么要计算b次,当幂值很大时,消耗时间也很大,那么有什么办法可以减少次数呢?
这就要用到快速幂了
快速幂采用分治的策略,一分为二, 二分为四,四分为八…
a ^ b =( (a ^2) ^ (b/ 2) ) * a ^ (b % 2) = (a ^ (b/2))^ 2 * a ^ (b % 2)
= ( a ^ (b/2) * a ^ (b /2) ) * a ^ (b % 2) … 接着不断的分治
比如计算2^4
正常迭代要计算四次
如果使用快速幂就先计算2^2,再计算(2 ^ 2)^2,这样就只计算了两次,当数据很大时就减少了迭代次数
代码如下
int fun(int a, int b)
{
int t;
if (b == 1)
{
return a;
}
if (b % 2 == 0)
{
t = fun(a, b / 2);
return t * t;
}
else {
t = fun(a, b / 2);
return t * t * a;
}
}
你以为这样就完了吗?
我们想想还能不能再优化
优化
还记得位运算吗?
我们把b看作一个二进制数,如果最后一位是1就把a乘到答案了,每遍历一个位数,就把a平方,这样就最大的减少了计算次数
int power(int a,int b)
{
int ans=1;
for(;b;b=b>>1)//这里的中间单独一个b是判断b是否不为零
{
if(b&1)ans=ans*a;
a=a*a;
}
return ans;
}
举个例子
比如说求a的11次方,11转化成二进制是1011,那么就是a的1011次
1:1011&1=1;ans=a;a=a2
2:b=101;101&1=1;ans=a3; a=a4;
3:b=10;10&1=0;ans=a3;a=a8;
4:b=1;1&1=1;ans=a11;a=a22;
5:return ans;
洛谷有个模板题p1226
代码
#include<iostream>
using namespace std;
#define ll long long
ll power(ll a, ll b,ll k)
{
ll ans = 1%k;
for (; b; b = b >> 1)
{
if (b & 1)ans = ans * a%k;
a = a * a%k;
}
return ans;
}
int main()
{
ll b; ll p; ll k;
cin >> b >> p >> k;
ll s;
s = power(b, p, k);
cout << b << "^" << p << " mod " << k << "=" << s;
return 0;
}
矩阵快速幂
矩阵快速幂的原理和快速幂一样,只不过底数变成了一个矩阵
代码如下
struct mat//定义一个矩阵
{
int m[20][20];
}x,y;
mat mul(mat x, mat y,int n)//定义矩阵乘法,n为矩阵大小
{
mat temp;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
for (int k = 1; k <= n; k++)
temp.m[i][j] = temp.m[i][j] + (x.m[i][k] * y.m[k][j]);
/*temp.m[i][j] = (temp.m[i][j] + (x.m[i][k] * y.m[k][j]) % mod) % mod;*/
/*如果题目没说或者数据较小,可以不取余*/
return temp;
}
mat matpower(mat a, int b, int n)//计算a^b,n为矩阵大小
{
mat ans;
for (int i = 1; i <= n; i++)//构造单位矩阵
ans.m[i][i] = 1;
while (b) {
if (b & 1)
ans = mul(ans, a, n);
a = mul(a, a, n);
b >>= 1;
}
return ans;
}
模板题p3390
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
const int syk = 1e9 + 7;
ll a[105][105], b;
int n;
ll ans[105][105] = { 0 };
inline void mul1() {
ll c[105][105] = { 0 };
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
c[i][j] = (c[i][j] + ans[i][k] * a[k][j]) % syk; //注意膜1e9+7
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
ans[i][j] = c[i][j];
}
}
}
inline void mul2() {
ll c[105][105] = { 0 };
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
c[i][j] = (c[i][j] + a[i][k] * a[k][j]) % syk;
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
a[i][j] = c[i][j];
}
}
}
int main() {
cin >> n >> b;
for (register int i = 1; i <= n; i++) {
for (register int j = 1; j <= n; j++)
cin >> a[i][j];
}
for (register int i = 1; i <= n; i++)
ans[i][i] = 1;
while (b) {
if (b & 1)
mul1();
mul2();
b >>= 1;
}
for (register int i = 1; i <= n; i++) {
for (register int j = 1; j <= n; j++)
printf("%lld ", ans[i][j] % syk);
printf("\n");
}
return 0;
}