Solution - P2106 Sam数
yuruilin2026 神犇的一生之敌
一年半没有打矩阵快速幂了,手生了(悲)
思路
由题目相邻两位的数字之差不超过 2 一眼构造出转移矩阵:
\[\begin{bmatrix}
1 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
1 & 1 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\
1 & 1 & 1 & 1 & 1 & 0 & 0 & 0 & 0 & 0 \\
0 & 1 & 1 & 1 & 1 & 1 & 0 & 0 & 0 & 0 \\
0 & 0 & 1 & 1 & 1 & 1 & 1 & 0 & 0 & 0 \\
0 & 0 & 0 & 1 & 1 & 1 & 1 & 1 & 0 & 0 \\
0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 & 1 & 0 \\
0 & 0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 & 1 \\
0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 \\
0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 1 \\
\end{bmatrix}
\]
或者这么构造:
for(rint i = 0; i <= 9; ++i)
for(rint j = 0; j <= 9; ++j)
tmp.a[i][j] = (abs(i-j) <= 2);
然后转移 \(n-1\) 次就行了。注意到 \(n \le 10^{18}\),于是矩阵快速幂。
时间复杂度 \(\mathcal{O}(\log_2 n)\)。
代码
#include <bits/stdc++.h>
#define rint register int
#define rllong register long long
#define llong long long
#define mod 1000000007ll
using namespace std;
struct Martix{
llong a[10][10];
Martix operator*(const Martix& b){
Martix res;
memset(res.a, 0, sizeof res.a);
for(rint i = 0; i <= 9; ++i)
for(rint j = 0; j <= 9; ++j)
for(rint k = 0; k <= 9; ++k)
res.a[i][j] = (res.a[i][j]+a[i][k]*b.a[k][j])%mod;
return res;
}
} src, dp, tmp;
llong n, ans;
inline void prework();
int main(){
scanf("%lld", &n), --n; // 只转移 n-1 次
prework();
if(n == 0){puts("10"); return 0;} // 本来应该是 n = 1 时特判,但是已经 --n 了
while(n){
if(n & 1) dp = dp*tmp;
tmp = tmp*tmp, n >>= 1;
}
src = src*dp;
for(rint i = 0; i <= 9; ++i)
ans = (ans+src.a[0][i])%mod;
printf("%lld", ans);
return 0;
}
inline void prework(){
// Source
for(rint i = 1; i <= 9; ++i)
src.a[0][i] = 1;
// DP
for(rint i = 0; i <= 9; ++i)
for(rint j = 0; j <= 9; ++j)
dp.a[i][j] = (i == j);
// Temp
for(rint i = 0; i <= 9; ++i)
for(rint j = 0; j <= 9; ++j)
tmp.a[i][j] = (abs(i-j) <= 2);
return;
}

浙公网安备 33010602011771号