题目描述
解题思路
我们先看题目来列出这道题的递推式,因为一个点可以由它前
k
k
k个点中的任意一个点来得到,设守望者走到第
i
i
i号监狱需要
f
(
i
)
f(i)
f(i)步,那么
f
(
i
)
=
f
(
i
−
1
)
+
f
(
i
−
2
)
+
…
+
f
(
i
−
k
)
f(i)=f(i-1)+f(i-2)+…+f(i-k)
f(i)=f(i−1)+f(i−2)+…+f(i−k)。但是当
i
<
k
i<k
i<k时,
f
(
i
)
f(i)
f(i)就是一个前缀和了
如果细心一点观察,可以发现这个递推式和斐波那契数列有一点相像,因为数据范围太大,我们采用矩阵加速来解决
如果题目要求“闪烁”技能为 k k k级,那么我们就定义一个 A A A矩阵为 [ f ( 1 ) , f ( 2 ) … f ( k ) ] \begin{bmatrix}f(1), f(2)…f(k)\end{bmatrix} [f(1),f(2)…f(k)],那么我们需要让 A A A矩阵乘以一个 B B B矩阵使它变成 [ f ( 2 ) , f ( 3 ) … f ( k + 1 ) ] \begin{bmatrix}f(2),f(3)…f(k+1)\end{bmatrix} [f(2),f(3)…f(k+1)]
所以
B
B
B矩阵就因该为一个
k
∗
k
k*k
k∗k的矩阵,很容易想到
B
B
B矩阵的构造法:
1、最后一列全部为1
2、从第2行第2列开始,右下方的斜线上全部为1
即
B
B
B矩阵为:
[
0
,
0
,
0
,
0
…
0
,
1
1
,
0
,
0
,
0
…
0
,
1
0
,
1
,
0
,
0
…
0
,
1
…
…
0
,
0
,
0
,
0
…
1
,
1
]
\begin{bmatrix}0,0,0,0…0,1\\ 1,0,0,0…0,1\\ 0,1,0,0…0,1\\ ……\\0,0,0,0…1,1\end{bmatrix}
⎣⎢⎢⎢⎢⎡0,0,0,0…0,11,0,0,0…0,10,1,0,0…0,1……0,0,0,0…1,1⎦⎥⎥⎥⎥⎤
然后再用一个矩阵快速幂求解就可以了
参考代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define reg register
template <class T>
inline T read() {
T x = 0; T f = 1; char s = getchar();
while(s < '0' || s > '9') {if(s == '-') f = -1; s = getchar();}
while(s >= '0' && s <= '9') {x = (x << 3) + (x << 1) + s - 48; s = getchar();}
return x * f;
}
template <typename T>
inline void wri(T x) {
if(x < 0) {x = -x; putchar('-');}
if(x / 10) wri(x / 10);
putchar(x % 10 + 48);
}
template <typename T>
inline void write(T x, char s) {
wri(x);
putchar(s);
}
#define LL long long
const LL mod = 7777777;
LL k, n;
struct matrix {
int n, m;
LL a[15][15];
inline void cl() {
n = m = 0;
memset(a, 0, sizeof a);
}
inline matrix operator * (const matrix &rhs) const { //矩阵乘法
matrix ret;
ret.cl();
ret.n = n, ret.m = rhs.m;
for(reg int i = 1;i <= n;i ++)
for(reg int j = 1;j <= rhs.m;j ++)
for(reg int k = 1;k <= m;k ++)
ret.a[i][j] = (ret.a[i][j] + a[i][k] * rhs.a[k][j] % mod) % mod;
return ret;
}
}A, B, ans;
inline matrix qkpow(matrix x, LL y) { //矩阵快速幂
matrix ret;
ret.cl();
ret.n = x.n, ret.m = x.m;
for(reg int i = 1;i <= ret.n;i ++)
ret.a[i][i] = 1;
while(y) {
if(y & 1)
ret = ret * x;
x = x * x;
y >>= 1;
}
return ret;
}
int main() {
k = read<LL>(), n = read<LL>();
A.n = 1, A.m = k, B.n = B.m = k;
A.a[1][1] = 1;
int tmp = 1;
for(reg int i = 2;i <= k;i ++) { //矩阵初始化
A.a[1][i] = tmp;
tmp += A.a[1][i];
}
for(reg int i = 1;i <= B.m;i ++) {
if(i != B.m)
B.a[i + 1][i] = 1;
else
for(reg int j = 1;j <= B.n;j ++)
B.a[j][i] = 1;
}
ans = A * qkpow(B, n + 1 - k); //快速幂求解
write(ans.a[1][ans.m], '\n');
return 0;
}