蓝桥杯 算法提高 递推求值

题目如下:

问题描述
  已知递推公式:

  F(n, 1)=F(n-1, 2) + 2F(n-3, 1) + 5,

  F(n, 2)=F(n-1, 1) + 3F(n-3, 1) + 2F(n-3, 2) + 3.

  初始值为:F(1, 1)=2, F(1, 2)=3, F(2, 1)=1, F(2, 2)=4, F(3, 1)=6, F(3, 2)=5。
  输入n,输出F(n, 1)和F(n, 2),由于答案可能很大,你只需要输出答案除以99999999的余数。
输入格式
  输入第一行包含一个整数n。
输出格式
  输出两行,第一行为F(n, 1)除以99999999的余数,第二行为F(n, 2)除以99999999的余数。
样例输入
4
样例输出
14

21
数据规模和约定
  1<=n<=10^18。
-----分割线-----
  在拿到此题后,就知道这题应该是矩阵快速幂,但是因为以前只做过简单的斐波那契数列的矩阵快速幂,所以完全不知道这题该怎么构造矩阵,后来翻了百度上的很多博客。简单来说,就是找到一个矩阵A满足:x(n-1)*A=x(n)。当然,此题不同于一般的“x(n)、x(n-1)”。要做如下构造:
  [f(n-1,1),f(n-1,2),f(n-2,1),f(n-2,2),f(n-3,1),f(n-3,2),5,3]*A=[f(n,1),f(n,2),f(n-1,1),f(n-1,2),f(n-2,1),f(n-2,2),5,3]
  即把前三项当做x(n-1),后一项以及前三项的后两项当做x(n),易知矩阵为8阶矩阵,具体见代码:
#include<stdio.h>
#define max 99999999
#define ll long long int
typedef struct Matrix
{
    ll m[8][8];
}mat;
mat multi(mat x,mat y,int a,int b,int c)
{
    int i,j,k;
    mat z;
    for(i=0;i<8;i++)
        for(j=0;j<8;j++)
            z.m[i][j]=0;
    for(i=0;i<a;i++)
        for(j=0;j<c;j++)
            for(k=0;k<b;k++)
                z.m[i][j]=(z.m[i][j]+(x.m[i][k]*y.m[k][j])%max)%max;
    return z;
}
int main()
{
    ll n,v1,v2,i;
    mat A={ 0,1,1,0,0,0,0,0,
            1,0,0,1,0,0,0,0,
            0,0,0,0,1,0,0,0,
            0,0,0,0,0,1,0,0,
            2,3,0,0,0,0,0,0,
            0,2,0,0,0,0,0,0,
            1,0,0,0,0,0,1,0,
            0,1,0,0,0,0,0,1
                            };
    mat E={ 1,0,0,0,0,0,0,0,
            0,1,0,0,0,0,0,0,
            0,0,1,0,0,0,0,0,
            0,0,0,1,0,0,0,0,
            0,0,0,0,1,0,0,0,
            0,0,0,0,0,1,0,0,
            0,0,0,0,0,0,1,0,
            0,0,0,0,0,0,0,1,
                            };
    ll s[8]={6,5,1,4,2,3,5,3};
    scanf("%I64d",&n);
    if(n==1)
        printf("2\n3");
    if(n==2)
        printf("1\n4");
    if(n==3)
        printf("6\n5");
    if(n>=4)
    {
        n-=3;
        while(n)
        {
            if(n%2)
                E=multi(E,A,8,8,8);
            n/=2;
            A=multi(A,A,8,8,8);
        }
        v1=0;
        v2=0;
        for(i=0;i<8;i++)
        {
            v1=(v1+(s[i]*E.m[i][0])%max)%max;
            v2=(v2+(s[i]*E.m[i][1])%max)%max;
        }
        printf("%I64d\n%I64d",v1,v2);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/search-the-universe/p/holiday-4.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值