,快速乘,快速幂,矩阵快速幂(求斐波那契数列)

快速幂:

方法一::

首先快速幂有几个公式:

1.(a^b)mod c=( a mod c)^b mod c;

(ab) mod c=[(a mod c)*( b mod c)] mod c;    (积的取余等于取余的积取余)


快速幂算法依赖于一下两个公式:

a^b mod c=((a²)^(b/2)) mod c , b是偶数

a^b mod c=((a²)(b/2)*a) mod c ,b是奇数

有了上述两个公式,我们可以得出一下结论:

1.如果b是偶数,我们可以记k=a²modc,那么(k)^(b/2)mod c 就可以了.

2.如果b是奇数,我们也可以记k=a²modc,那么((k)^(b/2)mod c就可以了


所以有了最终的算法:快速幂算法(log b):

	int ans=1;
	a=a%c;
	while(b>0)
	{
		if(b%2==1)  ans=(ans*a)%c;
		b=b/2;
		a=(a*a)%c;
	}

将上述代码结构化,也就是写成函数:

int PowerMod(int a,int b,int c)
{
	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;
}

方法二::

用位运算来实现:

1.b&1(取b的二进制最低位(即第0位) 判断b是否为奇数,是则为1)

2.b>>1(去掉b的二进制最低位(即第0位))

所以代码实现为:

#include<iostream>
#include<cstdio>
using namespace std;
int pow3(int x,int n)
{

	if(n==0) return 1;
	else
	{
		while((n&1)==0)
		{

			n>>=1;
			x*=x;
		}
	}
	cout<<n<<endl;
	int result=x;
	n>>=1;
	while(n!=0)
	{

		x*=x;
		cout<<x<<endl;
		if((n&1)!=0)
			result*=x;
		n>>=1;
	}
	return result;
} 
int main()
{
	int x,n;
	cin>>x>>n;
	cout<<pow3(x,n)<<endl;
} 

矩阵快速幂:

矩阵快速幂其实就是矩阵相乘然后套用快速幂.这个首先来写一下矩阵相乘

const int N=100;
int c[N][N];
void multi(int a[][N],int b[][N],int n)
{
    memset(c,0,sizeof c);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        for(int k=1;k<=n;k++)
        c[i][j]+=a[i][k]*b[k][j];
}

然后了解一下矩阵相乘原理
: 两个相乘是要一行和一列对应乘,那么矩阵乘法是需要A的行数与B的列数相等的, 矩阵快速幂只会用到方阵(n*n)

矩阵快速幂是用来求解递推式的,所以第一步先要列出递推式:

 f(n)=f(n-1)+f(n-2)

第二步是建立矩阵递推式,找到转移矩阵:

,简写成T * A(n-1)=A(n),T矩阵就是那个2*2的常数矩阵,而

这里就是个矩阵乘法等式左边:1*f(n-1)+1*f(n-2)=f(n);1*f(n-1)+0*f(n-2)=f(n-1);

所以这里相乘就是矩阵n-1次相乘,然后输出第一行第二个元素,也就是a[0][1]

这里可以练习一下poj 3070,其实就是矩阵快速幂的模板题




然后给一些简单的递推式:
1.f(n)=a*f(n-1)+b*f(n-2)+c;(a,b,c是常数)


2.f(n)=c^n-f(n-1) ;(c是常数)



快速乘:

问题:

  求 (a*b) % m 的值,其中 a,b,m 是1到10^18。

  如果直接乘的话,因为a和b还有m都很大,那么会溢出long long,所以需要一些方法。

  朴素的想法是用数组模拟高精度,但是比较麻烦。

 

  还有更好的方法:

  求乘法的列竖式,

  1234*213=1234*3+1234*10*1+1234*10^2*2;

  那么如果变成二进制的话 10101 × 1011 = 10101*1+10101*2^1*1+10101*2^2*0+10101*2^3*1;

  这样代码如下:

long long multi(long long a,long long b,long long m) {
    long long ans=0;

    while(b) {
        if(b&1) (ans+=a) %= m;
        (a=a*2) %= m;
        b/=2;
    }

    return ans;
}



  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值