FZU 1683 纪念SlingShot

题目描述:

点击打开链接

一道标准的模版化的矩阵快速幂,简单说一下矩阵快速幂,矩阵快速幂主要是用于加速递推式的计算,举个例子,斐波那契数列fib[n]=fib[n-1]+fib[n-2],第n项需要用到后面两项,那么先构造一个2行的矩阵(1)。
fib[n-1]
fib[n-2]

我们还需要一个2*2的矩阵,希望这两个矩阵相乘能够算出fib[n]的结果,同时要保证我算出来的矩阵能够继续递推fib[n+1]的答案,所以算出的矩阵的第二行应该为fib[n-1],那么接下来根据各项系数我们可以很容易的构造出这个矩阵(2)如下
1
1
1
0
这时我们可以发现我们用初始矩阵不断去和这个矩阵进行矩阵乘法,就可以递推出fib[n],fib[n+1],fib[n+2]....的值,那么我们可以将初始矩阵(3)设为
fib[2]
fib[1]

那么我要计算fib[n]的值,只需要将这个矩阵去和矩阵(2)进行n-2次矩阵相乘就行了,所以此时就是要算矩阵(2)的n-2次幂,高次幂的写法模仿快速幂去写就行了
最后回到这题,用如上方法就可以很容易的构造出我们需要的矩阵
f(2)
f(1)
f(0)
sum(2)
3
2
7
0
1
0
0
0
0
1
0
0
3
2
7
1
结果就是矩阵(1)*矩阵(2)^(n-2)的最后一行
AC代码:
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int MOD=2009;

struct MAT
{
    long long s[4][4];
    MAT ()
    {
        memset(s,0,sizeof(s));
    }
    void init()
    {
        s[0][0]=3;s[0][1]=2;s[0][2]=7;s[0][3]=0;
        s[1][0]=1;s[1][1]=0;s[1][2]=0;s[1][3]=0;
        s[2][0]=0;s[2][1]=1;s[2][2]=0;s[2][3]=0;
        s[3][0]=3;s[3][1]=2;s[3][2]=7;s[3][3]=1;
    }
};

long long n;

MAT MAT_MUL(MAT &m1,MAT &m2)
{
    MAT m3;
    for (int i=0;i<4;i++)
    {
        for (int j=0;j<4;j++)
        {
            for (int k=0;k<4;k++)
                m3.s[i][j]=(m3.s[i][j]+m1.s[i][k]*m2.s[k][j])%MOD;
        }
    }
    return m3;
}
MAT MAT_POW(MAT m1,MAT m2,int x)
{
    while(x)
    {
        if (x&1) m2=MAT_MUL(m1,m2);
        m1=MAT_MUL(m1,m1);
        x=x>>1LL;
    }
    return  m2;
}
int main()
{
    int T;
    scanf("%d",&T);
    int cas=1;
    while(T--)
    {
        scanf("%lld",&n);
        if (n==0) {printf("Case %d: 1\n",cas); cas++; continue;}
        if (n==1) {printf("Case %d: 4\n",cas); cas++; continue;}
        if (n==2) {printf("Case %d: 9\n",cas); cas++; continue;}
        MAT m1;
        m1.init();
        MAT m2;
        for (int i=0;i<4;i++)
            for (int j=0;j<4;j++)
            if (i==j) m2.s[i][j]=1;
        MAT m3=MAT_POW(m1,m2,n-2);
        long long ans=0;
        ans=(ans+5*m3.s[3][0])%MOD;
        ans=(ans+3*m3.s[3][1])%MOD;
        ans=(ans+1*m3.s[3][2])%MOD;
        ans=(ans+9*m3.s[3][3])%MOD;
        printf("Case %d: %lld\n",cas,ans);
        cas++;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值