2016 沈阳 1003 Recursive sequence(hdu 5950)矩阵快速幂

106 篇文章 0 订阅
4 篇文章 0 订阅

题意:

给出f[1]=a;f[2]=b;f[n]=f[n-1]+2*f[n-2]+i*i*i*i;问f[n]对2147493647取模的值,n的范围到2的31次。


思路:

由于n的范围过大,必须要用矩阵快速幂求解。难点在于构造矩阵。一开始我的想法是把i的四次分别用(i-1)的四次、三次、二次、一次、零次表示,来构造矩阵,结果一直错,后来看了网上有人是把i+1的四次用i来表示来构造的矩阵,于是我换了下矩阵,就过了,至今不明白原来构造的矩阵为什么就不行。

矩阵如下:



ps: 2147493647记得用 unsigned int,别问我为什么知道QAQ


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const unsigned int mod=2147493647;
struct p
{
    long long x[8][8];
} u, o;
void init(long long r[][10], long long y[][10])
{
    int i, j;
    for(i=0; i<=6; i++)
    {
        for(j=0; j<=6; j++)
        {
            u.x[i][j]=y[i][j];
        }
    }
    for(i=0; i<=6; i++)
    {
        for(j=0; j<=6; j++)
        {
            o.x[i][j]=r[i][j];
        }
    }
}
p multi(p a, p b)
{
    int i, j, k;
    p c;
    for(i=0; i<7; i++)
    {
        for(j=0; j<7; j++)
        {
            long long sum=0;
            for(k=0; k<=6; k++)
            {
                sum=(sum+(a.x[i][k]*b.x[k][j])%mod)%mod;
            }
            c.x[i][j]=sum;
        }
    }
    return c;
}
p  rec_quickmod(p a, int n)
{
    p b;
    memset(b.x, 0, sizeof(b.x));
    int i, j;
    for(i=0; i<=6; i++)b.x[i][i]=1;
    while(n)
    {
        if(n%2)b=multi(b,a);
        n/=2;
        a=multi(a,a);
    }
    return b;
}
int main()
{
    int t;
    scanf("%d",&t);
    int i, j;
    long long x[8][10]= {{1,1,0,0,0,0,0}, {2,0,0,0,0,0,0}, {1,0,1,0,0,0,0}, {0,0,4,1,0,0,0}, {0,0,6,3,1,0,0}, {0,0,4,3,2,1,0},{0,0,1,1,1,1,1}};
    long long y[8][10]= {{0,0,81,27,9,3,1}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}};
    while(t--)
    {
        int n;
        long long a, b;
        scanf("%d%lld%lld", &n, &a, &b);
        if(n==1){printf("%lld\n", a);continue;}
        if(n==2){printf("%lld\n", b);continue;}
        y[0][0]=b;
        y[0][1]=a;
        init(x, y);

        p c=rec_quickmod(o,n-2);

        p ans=multi(u,c);
//         for(i=0; i<7; i++)
//        {
//            for(j=0; j<7; j++)
//            {
//                printf("%lld ", ans.x[i][j]);
//            }
//            printf("\n");
//        }
        printf("%lld\n", ans.x[0][0]);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值