1. 程式人生 > >,快速乘,快速冪,矩陣快速冪(求斐波那契數列)

,快速乘,快速冪,矩陣快速冪(求斐波那契數列)

快速冪:

方法一::

首先快速冪有幾個公式:

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;
}