快速幂
计算a的b次幂对c取模!
我们能想到的就是暴力;
循环b次,每次乘以a就得到了答案;
但是如果b的值很大呢?这种O(n)的算法就太慢了!
下面-快速幂上场
首先了解一下下面这两个公式
接下来先直接给你们贴代码
int PowerMod(int a, int b, int c)//计算a的b次幂对c取模(复杂度lgb)
{
int ans = 1;
a = a % c;
while(b>0)
{
if(b % 2 = = 1)
ans = (ans * a) % c;
b = b/2;
a = (a * a) % c;
}
return ans;
}
是不是很神奇?为什么就变成了logn复杂度呢?其实关键在于b=b/2;为什么要这样写呢??我举个例子
我们要计算2^8,按照先前的算法我们需要循环8次。快速幂就是:计算2的4次幂可以由2的2次幂乘以2的2次幂,八次幂就是由二的四次幂乘以二的四次幂!!!!!!(懂了吗兄弟???当你数字很大的时候就是奇效!!你可以用手写一个很大的数按照快速幂算法算一下 复杂度不高的 一定要试试你才会体会到快速幂的奥妙)
矩阵快速幂
好难理解啊。。。好吧不吓唬你,其实入门还是很简单的!!
首先你需要有点线代基础知识!!(既然我写出来了我就给你来点矩阵快速幂需要的线代基础知识)
矩阵是什么你应该知道!!对!你肯定知道!我不会告诉你矩阵就是一个二维数组只是他有自己的一套运算规律
加减都是位置对应得的一项直接相加减
乘法如下(不一样)
举例:A、B均为3*3的矩阵:C=A*B,下面的代码会涉及到两种运算顺序,第一种就是直接一步到位求,第二种就是每次求一列,比如第一次,C00+=a00*b00,C01+=a00*b01……第二次C00+=a00*b10,C01+=a01*b11……以此类推。。。
C00 = a00*b00 + a01*b10 + a02*b20
C01 = a00*b01 + a01*b11 + a02*b21
C02 = a00*b02 + a01*b12 + a02*b22
C10 = a10*b00 + a11*b10 + a12*b20
C11 = a10*b00 + a11*b11 + a12*b21
C12 = a10*b02 + a11*b12 + a12*b22
C20 = a20*b00 + a21*b10 + a22*b20
C21 = a20*b01 + a21*b11 + a22*b21
C22 = a20*b02 + a21*b12 + a22*b22
C00 = a00*b00 + a01*b10 + a02*b2
C01 = a00*b01 + a01*b11 + a02*b21
C02 = a00*b02 + a01*b12 + a02*b22
(注释一下AB是矩阵A和矩阵B相乘,a是A的元素,aij是位置【i,j】的值,b自己类比)
好了下面那开始讲解矩阵快速幂(仅仅入门 难点的我做个几十道题了再发出来)
首先你要构造一个单位的矩阵(我也不知道怎么构造,因为这个没有板子,只能靠题目来构造,这个是我觉得矩阵快速幂唯二难得地方)
单位矩阵: n*n的矩阵 mat ( i , i )=1; 任何一个矩阵乘以单位矩阵就是它本身 n*单位矩阵=n, 可以把单位矩阵等价为整数1。(单位矩阵用在矩阵快速幂中)
7*7的单位矩阵
快速幂的思路就是:
设A为矩阵,求A的N次方,N很大,随便你怎么大1000000好吧。
先看小一点的,A的9次方
A^9
= A*A*A*A*A*A*A*A*A 【一个一个乘,要乘9次】
= A*(A*A)*(A*A)*(A*A)*(A*A)【保持格式的上下统一,所以加上这句】
= A*(A^2)^4 【A平方后,再四次方,还要乘上剩下的一个A,要乘6次】
= A*((A^2)^2)^2【A平方后,再平方,再平方,还要乘上剩下的一个A,要乘4次】
也算是一种二分思想的应用吧,1000000次幂,暴力要乘1000000次,快速幂就只要(log2底1000000的对数) 次。懂了吗??你肯定都懂!!
好了对于斐波数列(别tm给我说你不知道这个数列)我就直接上代码了(代码上有很详细的解释)
#include<bits/stdc++.h>///我图省事才写的万能头文件(不建议,做题多一点的都知道有的oj打不开)
using namespace std;
typedef long long ll;
const int MOD=10000;
struct mat
{
ll a[2][2];///自行改变,要用多大看题目
};
mat mat_mul(mat x,mat y)///矩阵相乘返回一个矩阵
{
mat res;///需要返回的用于存储积的矩阵
memset(res.a,0,sizeof(res.a));///清零无需多言
for(int i=0;i<2;i++)///小于2是由你的二维数组大小决定
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
res.a[i][j]=(res.a[i][j]+x.a[i][k]*y.a[k][j]);///前两个循环是为了确定下来所求矩阵元素,最后一个循环元素位置相关然后累加
///res.a[i][j]%=mod///取模,看题目需不需要
return res;
}
///求一个矩阵n次幂(参照求n的m次幂一样)
void mat_pow(int n)
{
mat c,res;
c.a[0][0]=c.a[0][1]=c.a[1][0]=1;
c.a[1][1]=0;
memset(res.a,0,sizeof(res.a));
for(int i=0;i<2;i++) res.a[i][i]=1;
while(n)
{
if(n&1) res=mat_mul(res,c);
c=mat_mul(c,c);
n=n>>1;
}
printf("%I64d\n",res.a[0][1]);
}
int main()
{
int n;
while(~scanf("%d",&n)&&n!=-1)
{
mat_pow(n);
}
return 0;
}
我知道你肯定想知道为什么要单位矩阵啊??为什么
我告诉你,因为他是多维的!
给你摆一个东西你自己体会一下
好了 你肯定懂了 bb!