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;
}

posted @ 2025-04-22 22:16  Hootime  阅读(5)  评论(0)    收藏  举报