莫拉莱斯的矩阵难题
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;
}