2008 Round 1A C Numbers (矩阵快速幂)

题目描述:

请输出(3+√5)^n整数部分最后3位。如果结果不超过2位,请补足前导0.

分析:

我们最容易想到的方法肯定是直接计算这个表达式的值,但是这样的精度是不够的。朴素的算法没有办法得到答案。但是我们根据分析可以发现这个问题不用求出√5的值也可以得到答案。

我们可以发现,将(3+√5)^n这个式子展开后就是An+Bn√5的形式。同样的,我们将(3-√5)^n这个式子展开后就是An-Bn√5。

因此,(3+√5)^n+(3-√5)^n=2An是一个整数,其中0<(3-√5)^n <1,是解题的关键。由于(3+√5)^n=2An-(3-√5)^n,所以(3+√5)^n的整数部分就是2An-1.

根据上面的推导,只要高效的求出An就可以解决这个问题了。由于(3+√5)^(n+1)=(3+√5)(3+√5)^n=(3+√5) (An+Bn√5),我们可以得到An,Bn,A(n+1),B(n+1)的递推关系。

A(n+1)=3An+5Bn;

B(n+1)=An+3Bn;

A0=1 B0=0;

我们可以用矩阵表示这个递推关系,因此可以使用快速幂运算。因为结果要求的是后三位,所以最后取余1000就行。

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
struct Node
{
    int e[2][2];
    Node()
    {
        memset(e,0,sizeof(e));
    }
};
Node mul(Node a,Node b)
{
    Node c;

    for(int i=0; i<2; i++)
        for(int j=0; j<2; j++)
            for(int k=0; k<2; k++)
            {
                c.e[i][j]+=(a.e[i][k]*b.e[k][j]);
            }
    return c;
}

Node quick_mi(Node a,int b)
{
    Node c;
    c.e[0][0]=1;
    c.e[1][1]=1;
    while(b)
    {
        if(b&1)
            c=mul(c,a);
        b>>=1;
        a=mul(a,a);
    }
    return c;
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        Node A;
        A.e[0][0]=3;
        A.e[0][1]=5;
        A.e[1][0]=1;
        A.e[1][1]=3;
        A=quick_mi(A,n);
        printf("%03d
",(2*A.e[0][0]-1)%1000);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/cmmdc/p/7297810.html