矩阵快速幂

http://acm.bjfu.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1440

题目意思简单的不能再简单,但是 以前从来没有接触过这一类型的题目,怎么做都感觉做不出来。 先引进几个知识点吧:
1——-快速幂模板:

原理: n*n*n*n…….n (m个n相乘);
设最后的结果为ans ,所以 ans=1*(m个n);
———————–|(循环)
| if(n是奇数),把一个n放进ans中,ans=n*(m-1个n);
| 这时 把 n 变成 n*n , 所以m变成 m/2;
| 所以等式就变成 ans=n*((m-1)/2个 n*n)
———————–| (循环) 直到 m=0停止
当然以上步骤一般是要取mod的,因为m会很大。
代码:
__int64 fast_pow(__int64n,__int64m)
{
__int64 ans=1;
while(m)
{
if(m%2==1)
{
ans*=n;
ans%=mod;
}
n*=n;
n%=mod;
m/=2;
}
return ans;
}
2—–矩阵相乘
矩阵 a * 矩阵b=a的行*b的列
如 |1 2 | | 5 6 | |1* 5+2 * 7 1*6+2 * 8 |
如 |3 4| * | 7 8 | =|3* 5+4* 7 3*6+4 * 8|
模板:
struct matr{
__int64 an[maxn][maxn] //(这里的maxn表示矩阵的行,列,不同情况 还需自己分析)
}base,ans; //(base 是拿来做快速幂的底数 ,ans是快速幂的结果)
matr mul(matr a,matr b)
{
matr c;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
{
c.an[i][j]=0;
for(int k=0;k<2;k++)
c.an[i][j]+=a.an[i][k]*b.an[k][j];
c.an[i][j]%=maxn;
}
return c;
}
接下来就是矩阵快速幂了:
__int64 fast_mul(__int64 n)
{
(给base赋好初值)
(给ans赋好初值)
while(n)
{
if(n&1)
ans=mul(temp,ans) // 这里很重要:一定要搞清楚 temp在前 还是ans 在前, 之前就因为这出过错
n/=2;
base=mul(base,base);
}
return ans.an[i][j] //(这个i,j 因你给ans 赋初值的时候订,可能在任何位置)
}

这就写完了,再讲一下原理吧,和适用题目吧:
比如说 求n=100000000000 …… 0 的斐波那契数列 - -或者 a[n]=x*a[n-1]+y*a[n-2];
矩阵
|a[n] |………… |x y |……….. |a[n-1] |…… |x* a [n-1] + y*a[n-2] |
|a[n-1] | = | 1 0 | * |a[n-2] | = | 1*a[n-1] |
如此一来 求第n个 只需将 base进行n-1或者n-2 次幂运算即可(具体情况看赋给base,ans的初值)

using namespace std;
#define maxn 1000000007
struct matr
{
   __int64 an[2][2];
}temp,ans;
matr mul(matr a,matr b)
{
    matr c;
    for(int i=0;i<2;i++)
        for(int j=0;j<2;j++)
        {
            c.an[i][j]=0;
            for(int k=0;k<2;k++)
               c.an[i][j]+=a.an[i][k]*b.an[k][j];
            c.an[i][j]%=maxn;
        }
    return  c;
}
__int64 fast(__int64 n)
{
     temp.an[0][0]=2;
     temp.an[0][1]=2;
     temp.an[1][0]=1;
     temp.an[1][1]=0;
     ans.an[0][0]=8;
     ans.an[1][0]=3;
     ans.an[0][1]=0;
     ans.an[1][1]=0;
     while(n)
     {
         if(n%2==1)
         {
             ans=mul(temp,ans);
         }
         n/=2;
         temp=mul(temp,temp);
     }
     return ans.an[0][0];
}
int main() {
    __int64 n;
    //freopen("1.txt","r",stdin);
    while(~scanf("%I64d",&n)){
        if(n==1)
        {
            printf("3\n");
            continue;
        }
        printf("%I64d\n",fast(n-2));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值