描述
题解
这个题是矩阵快速幂问题,给定若干个上界,每个上界都是有一定宽度的,这些上界在 x 轴的投影是连续的,要我们从 (0,0) 移动到 (k,0) ,每次只能向右、右上、右下移动,所以呢,这个其实和 《机器人走方格》有些相似,不过他是给定了连续的若干个矩形区域(每个上界和 x 轴之间的区域),需要求这些区域合并在一起后的方案数,另外这里我们的 k 是很大的,所以必须使用矩阵快速幂了。
因为上界最大为
15
,所以我们需要构造一个
16∗16
的矩阵进行快速幂,这个矩阵的样子大概是酱紫的:
A=⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢1100……0001110……0000111……0000011……000………………………………………………0000……1100000……1110000……011⎤⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥
这也是本题的核心,构造出来这个矩阵,也就好写多了……
剩下的就看看代码吧,没有什么稀奇古怪的了,注意数据类型。
代码
#include <cstdio>
#include <cstring>
#define mod(x) ((x) % MOD)
using namespace std;
typedef long long ll;
const ll MOD = 1e9 + 7;
const int MAX_MAT_SIZE = 16;
typedef struct Matrix
{
ll m[MAX_MAT_SIZE][MAX_MAT_SIZE];
} mat;
mat A, B, pre, unit;
mat matrix_mul(mat a, mat b, int len)
{
mat ret;
memset(ret.m, 0, sizeof(ret.m));
for (int k = 0; k <= len; k++)
{
for (int i = 0; i <= len; i++)
{
if (a.m[i][k])
{
for (int j = 0; j <= len; j++)
{
ret.m[i][j] = mod(ret.m[i][j] + (ll)a.m[i][k] * b.m[k][j]);
}
}
}
}
return ret;
}
void init()
{
memset(A.m, 0, sizeof(A.m));
for (int i = 0; i < MAX_MAT_SIZE; i++)
{
for (int j = i - 1; j < i + 2 && j < MAX_MAT_SIZE; j++)
{
if (j >= 0)
{
A.m[i][j] = 1;
}
}
}
memset(unit.m, 0, sizeof(unit.m));
for (ll i = 0; i < MAX_MAT_SIZE; i++)
{
unit.m[i][i] = 1;
}
memset(pre.m, 0, sizeof(pre.m));
pre.m[0][0] = 1;
}
Matrix matrix_quick_power(mat a, ll k, int len)
{
mat ret = unit;
while (k)
{
if (k & 1)
{
ret = matrix_mul(a, ret, len);
}
a = matrix_mul(a, a, len);
k >>= 1;
}
return ret;
}
int n;
ll k;
int main()
{
init();
scanf("%d%lld", &n, &k);
ll a, b;
int c, flag = 0;
for (int i = 1; i <= n; i++)
{
scanf("%lld%lld%d", &a, &b, &c);
if (b > k)
{
b = k;
flag = 1;
}
B = matrix_quick_power(A, b - a, c);
for (int j = c + 1; j < MAX_MAT_SIZE; j++)
{
pre.m[j][0] = 0;
}
B = matrix_mul(B, pre, c);
for (int j = 0; j <= c; j++)
{
pre.m[j][0] = B.m[j][0];
}
if (flag == 1)
{
break;
}
}
printf("%lld\n", B.m[0][0]);
return 0;
}