Funny Function————(hdu6050)矩阵快速幂


题目: 点击打开链接


  
  
这道题可以利用矩阵快速幂做 但是有些大神硬推公式就推出来了,佩服佩服
利用第一行F(1,k)推导可以发现当j为奇数(F(i,1)+F(i,2)+……+F(i,j))=F(i,j+1)-F(i,2)+F(i,1);
当j为偶数的时候 (F(i,1)+F(i,2)+……+F(i,j))=F(i,j+1)-F(i,1);
当n为偶数的时候我们进行(两行为一个矩阵运算)
{F(i,1)}={F(i-1,n+1)-F(i-1,1)}={F(i-1,n+1)}-{F(i-1,1)}
F(i,2) F(i-1,n+2)-F(i-1,2) F(i-1,n+2) - F(i-1,2)
{F(i-1,n+1)}={0 1}{F(i-1,n)} = {0 1}^n{F(i-1,1)}
F(i-1,n+2) 2 1 F(i-1,n+1 2 1 F(i-1,2)
{F(i,1)}=[{0 1}^n-{1 0}]{F(i-1,1)}
F(i,2) 2 1 0 1 F(i-1,2)
{F(i,1)}=[{0 1}^n-{1 0}]^(m-1){F(1,1)}
 F(i,2)    2 1     0 1         F(1,2)

  
  
同理n为奇数的时候同理矩阵那个
{F(i,1)}=[{0 1}^n-{-1 1}]^(m-1){F(1,1)}
 F(i,2)    2 1      2 0         F(1,2)

然后直接快速幂
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;


typedef long long ll;
const ll mod=1e9+7;
struct matrix
{
    ll f[2][2];
};
matrix mul(matrix a,matrix b)
{
    matrix ans;
    memset(ans.f,0,sizeof(ans.f));
    for(int i=0; i<2; i++)
    {
        for(int j=0; j<2; j++)
        {
            for(int k=0; k<2; k++)
            {
                ans.f[i][j]=(ans.f[i][j]+a.f[i][k]*b.f[k][j]%mod)%mod;
            }
        }
    }
    return ans;
}
matrix pow(matrix a, ll p)
{
    matrix res;
    memset(res.f,0,sizeof(res.f));
    for(int i=0; i<2; i++)
        res.f[i][i]=1;
    while(p)
    {
        //cout<<"___"<<endl;
        if(p&1)
            res=mul(res,a);
        p>>=1;
        a=mul(a,a);
    }
    return res;
}
int main()
{
    int T;
    scanf("%d",&T);
    ll n,m;
    while(T--)
    {
        scanf("%lld%lld",&n,&m);
        //cout<<n<<" "<<m<<endl;
        if(n%2==1)
        {
            matrix a;
            a.f[0][0]=0;
            a.f[0][1]=1;
            a.f[1][0]=2;
            a.f[1][1]=1;
            a=pow(a,n);
            a.f[0][0]+=1;
            a.f[0][1]-=1;
            a.f[1][0]-=2;
            a=pow(a,m-1);
            printf("%lld\n",(a.f[0][0]+a.f[0][1])%mod);
        }
        else
        {
            matrix a;
            a.f[0][0]=0;
            a.f[0][1]=1;
            a.f[1][0]=2;
            a.f[1][1]=1;
            a=pow(a,n);
            a.f[0][0]-=1;
            a.f[1][1]-=1;
            a=pow(a,m-1);
            printf("%lld\n",(a.f[0][0]+a.f[0][1])%mod);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值