莫拉莱斯的矩阵难题(快速幂+规律)

莫拉莱斯的矩阵难题
Problem:D
Time Limit:1000ms
Memory Limit:65535K
Description
莫拉莱斯见到了一个数阵:

他觉得这个数阵似曾相识(如果你不觉得或者没有找到规律,请注意观察相邻两行),于是有了一个新想法:建立一个新的数阵,在第一层有且仅有一个初始数据Q,按照 类似于 上图的数阵的规律为接下来的几层构造数据,但是,不同的是,莫拉莱斯规定奇数层遵循规律A,偶数层遵循规律B。

莫拉莱斯决定将这个数阵称为“米格灾厄阵”,下面是初始数据为1时所呈现的部分米格灾厄阵:

莫拉莱斯想请你帮他计算一下在第i层中某个数有多少个(假定初始数据所在层数为第一层)。
约定所有数据均为整数,1<Q<1e10,1<i<1e18,1<x<1e10。
Input
输入数据仅有一行,包含三个整数Q,i,x,以空格分隔。Q为米格灾厄阵的初始数据。
Output

输出一行,仅有一个整数,表示在第i层中x的数量。

由于输出数据较大,请将输出数据对20200501取模的结果。
Sample Input
样例输入1:2 2 2

样例输入2:2 14 5
Sample Output
样例输出1:1

样例输出2:12
Hint
对于样例1的说明:

构造出的米格灾厄阵的前两层为

2
1 2

所以第2层中2的数量为1。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
const long long Mod = 20200501;
const long long pows[4][4] = {{0, 0, 0, 0}, {0, 1, 1, 0}, {0, 1, 0, 0}, {0, 1, 0, 1}};  //矩阵F
const long long start[4][4] = {{0, 0, 0, 0}, {0, 1, 0, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}}; //矩阵A
const long long _01[4][4] = {{0, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}};   //矩阵的0次方
class node
{ //矩阵类
public:
    long long arr[4][4];
    node(void) { memset(arr, 0, sizeof(arr)); }
    node(const long long a[4][4])
    { //构造函数
        for (register int i = 1; i <= 3; ++i)
            for (register int j = 1; j <= 3; ++j)
                arr[i][j] = a[i][j];
    };
    friend node operator*(const node &x, const node &y)
    { //重载乘法运算
        node c;
        for (register int i = 1; i <= 3; ++i)
            for (register int j = 1; j <= 3; ++j)
                for (register int k = 1; k <= 3; ++k)
                    c.arr[i][j] += x.arr[i][k] * y.arr[k][j];
        return c;
    }
    node operator%(long long mod)
    { //重载模运算
        node c;
        for (register int i = 1; i <= 3; ++i)
            for (register int j = 1; j <= 3; ++j)
                c.arr[i][j] = arr[i][j] % mod;
        return c;
    }
} task(pows), st(start);
const node zero(_01);
node pow(node a, long long b, long long mod)
{ //精简的快速幂
    if (b == 0)
        return zero; //矩阵的0次方
    if (b == 1)
        return a;
    node t = pow(a, b >> 1, mod);
    if ((b & 1) == 1)
        return (((t * t) % mod) * a % mod);
    return t * t % mod;
}
int main(void)
{
    long long a, b, c;
    scanf("%lld%lld%lld", &a, &b, &c);
    b--;
    long long ans = (a == c);
    if (c == 3) //3那一列从3开始+1
        ans += (b > 2);
    if (c == 5)
    {
        if (b == 5)
            ans += 1;
        else if (b >= 6)
            ans += (st * pow(task, ((b - 5) >> 1), Mod)).arr[1][1];
        //不能写成 pow(task,((b-5)>>1),Mod)*st 因为矩阵乘法不满足交换律
    }
    if (c == 7)
    {
        if (b == 7)
            ans += 1;
        else if (b >= 8)
            ans += (st * pow(task, ((b - 7) >> 1), Mod)).arr[1][1];
    }
    printf("%lld", ans % Mod);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值