快速幂+POJ3070

之前一直听说快速幂算法,但是也一直没有看过(好吧就是自己懒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感觉自己真是垃圾啊,有不对的还请大佬们指正,感谢!

呼呼呼写完了真开心要去睡觉了

猜你喜欢

转载自blog.csdn.net/destiny1507/article/details/80664896