之前一直听说快速幂算法,但是也一直没有看过(好吧就是自己懒emmmm),上周月赛真的是沉重的打击啊,所以就好好的看了一下这个算法,整数快速幂和矩阵快速幂,反正思想都是一样的。
先看整数快速幂:
如果我们要算一个数的19次方,很简单,一个for循环不就好了嘛,但是如果是1900、1900000、19000000000呢?显然花费的时间就不是很乐观了,而用的时间多是因为乘的次数也就是计算的次数多,那么,如果我们用1+2+4+8+4来计算19次方呢?比起之前计算的19次,只要算5次就好了,当数据比较大时显然时间是会省很多的。
而整数快速幂的思想就是看数字的0 1表示,然后按位运算,比如算3的19次方,19是10011,就是2^4+2^1+2^0,起初让base=2^0=1,当你算的这一位是0,就可以跳过,只让base成倍增大,(因为你算下一位时base=base*3),当这一位是1的时候就乘上。
下面是整数快速幂的模板代码:
#include <iostream>
int mian(void)
{
int a,b;
scanf("%d%d",&a,&b);//计算a的b次方
int re=1;
while(b)
{
if(b&1)//看b的二进制表示 现在运算的这一位是0还是1
{
re=re*a;
}
a=a*a;
b/=2;//b右移
}
printf("%d\n",re);
return 0;
}
矩阵快速幂的计算方法和整数快速幂其实是一样的,只不过把数的乘法换成了矩阵运算而已。(矩阵乘法如果不太清楚的请自行百度)……但是矩阵快速幂之所以叫矩阵快速幂(肯定还是有不一样的嘛)它反映的其实是一种递推,其中最典型的就是斐波那契数列的求解问题。(POJ3070)下面结合例题来说。
In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn − 1 + Fn − 2 for n ≥ 2. For example, the first ten terms of the Fibonacci sequence are:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …
An alternative formula for the Fibonacci sequence is
.
Given an integer n, your goal is to compute the last 4 digits of Fn.
Input
The input test file will contain multiple test cases. Each test case consists of a single line containing n (where 0 ≤ n ≤ 1,000,000,000). The end-of-file is denoted by a single line containing the number −1.
Output
For each test case, print the last four digits of Fn. If the last four digits of Fn are all zeros, print ‘0’; otherwise, omit any leading zeros (i.e., print Fn mod 10000).
Sample Input
0
9
999999999
1000000000
-1
Sample Output
0
34
626
6875
Hint
As a reminder, matrix multiplication is associative, and the product of two 2 × 2 matrices is given by
.
Also, note that raising any 2 × 2 matrix to the 0th power gives the identity matrix:
.
其实题目有提示的,可以看这个矩阵
.
显然,需要算出
然后等式左边矩阵的第一行第一列就是递推下去的下一项。
这不是求n次方嘛,马上想到整数快速幂的思想
#include<iostream>
#include<cstdio>
#define maxn 3
using namespace std;
struct node
{
long long a[maxn][maxn];
};
node qmul(node g,node b){ //这个是矩阵的乘法运算,相当于整数快速幂中的乘上的那个数
node c;
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
c.a[i][j]=0;
for(int k=0;k<2;k++)
{
c.a[i][j]=(c.a[i][j]+(g.a[i][k]*b.a[k][j]))%10000;
//c.a[i][j]=c.a[i][j]%Mod;
}
}
}
return c;
}
node mul(node mid,long long n) //这个是中心思想,不过基本上和整数快速幂一样的
{
node temp;
for(int i=0;i<2;i++) //整数快速幂初始化为1,矩阵当然是初始化为单位阵啦
{
for(int j=0;j<2;j++){
temp.a[i][j]=(i==j); //temp这个单位阵相当于上面例子中的re了,乘法器(是叫这个名字吧Orz)
}
}
while(n)
{
if(n&1){
temp=qmul(temp,mid);
}
n/=2;
mid=qmul(mid,mid);
}
return temp;
}
int main(void)
{
long long n;
node mid; //定义了那个需要乘n次方的那个矩阵,相当于上面整数快速幂例子中的a
while(~scanf("%lld",&n))
{
if(n==0){
printf("0\n");
continue;
}
if(n==-1)
break;
mid.a[0][0]=1;mid.a[0][1]=1;
mid.a[1][0]=1;mid.a[1][1]=0;
node re=mul(mid,n);
printf("%lld\n",re.a[0][1]);
}
}
emmmmm感觉自己真是垃圾啊,有不对的还请大佬们指正,感谢!
呼呼呼写完了真开心要去睡觉了