矩阵快速幂(校赛)

题目描述:
天外天非常喜欢数列,现在averyboy给了天外天一个数列:F[n] = A * F[n - 1] + B * F[n - 2] + C * (n + 1) * (n - 2)(n >= 3)
其中F[1] = 1, F[2] = 2, 现在天外天把这个问题给你,对于给定N, A, B, C,你需要输出F[N], 因为答案很大,所以你需要对1000000007
取模。
输入描述:
第一行一个整数T,表示测试数据的组数。(T <= 100)
接下来T组测试数据,每组包括四个整数N, A, B, C;(N <= 1e18, A, B, C <= 1e5)
输出描述:
一个整数,F[N]对1000000007取模
样例输入:
4
1 1 1 1
2 1 1 1
3 1 1 1
4 1 1 1
样例输出:
Case #:1 1
Case #:2 2
Case #:3 7
Case #:4 19

第一次做快速幂的题

感觉就是从f(n-1)凑到f(n);



代码:
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const LL Mod = 1e9+7;
LL n,a,b,c;
struct ma
{
    LL m[5][5];
    ma()
    {
        memset(m,0,sizeof(m));
    }
};
ma mul(ma a,ma b)
{
    ma c;
    for(int i = 0;i < 5;i++)
        for(int j = 0;j < 5;j++)
        for(int k = 0;k < 5;k++)
        {
            c.m[i][j] += a.m[i][k]*b.m[k][j];
            if(c.m[i][j] < 0)
                c.m[i][j] = (c.m[i][j] + Mod) % Mod;
            c.m[i][j] = c.m[i][j] % Mod;
        }
    return c;
}
ma pow(ma a,LL n)
{
    ma c;
    for(int i = 0;i < 5;i++)
        c.m[i][i] = 1;
    while(n)
    {
        if(n&1)
            c = mul(c,a);
        n >>= 1;
        a = mul(a,a);
    }
    return c;
}
 int main()
 {
     freopen("C:\\Users\\hasee\\Desktop\\比赛\\题目\\F\\in.txt","r",stdin);
     freopen("C:\\Users\\hasee\\Desktop\\比赛\\题目\\F\\out1.txt","w",stdout);
     int T;
     scanf("%d",&T);
     int num = 1;
     while(T--)
     {
         scanf("%lld%lld%lld%lld",&n,&a,&b,&c);
         if(n == 1)
            printf("Case #:%d 1\n",num++);
         else if(n == 2)
            printf("Case #:%d 2\n",num++);
         else if(n == 3)
            printf("Case #:%d %lld\n",num++,(2*a + b + 4*c) % Mod);
         else
         {
             LL x1 = (2*a + b + 4*c) % Mod;
             ma m1,m2;
             m1.m[0][0] = a;
             m1.m[0][1] = b;
             m1.m[0][2] = c;
             m1.m[0][3] = 0;
             m1.m[1][0] = m1.m[2][2] = m1.m[2][3] = m1.m[3][3] = m1.m[3][4] = m1.m[4][4] = 1;
             m2.m[0][0] = x1;
             //cout<<"x1:"<<x1<<endl;
             m2.m[1][0] = 2;
             m2.m[2][0] = 10;
             m2.m[3][0] = 8;
             m2.m[4][0] = 2;
             m1 = pow(m1,n-3);
             m2 = mul(m1,m2);
             printf("Case #:%d %lld\n",num++,m2.m[0][0]);
         }
     }
     return 0;
 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值