[洛谷P2106]Sam數
阿新 • • 發佈:2018-11-28
題目大意:問長度為$n$的$Sam$數有幾個,$Sam$數的定義為沒有前導零,相鄰兩個數字之差絕對值小於等於$2$的數
題解:發現轉移方程一定,可以矩陣快速冪。
卡點:沒有特判$n=1$的情況
C++ Code:
#include <cstdio> const int mod = 1e9 + 7; inline int abs(int a) {return a < 0 ? -a : a;} inline void up(int &a, int b) {a += b - mod; a += a >> 31 & mod;} struct matrix { #define M 10 int s[M][M]; inline void E() { for (int i = 0; i < M; i++) s[i][i] = 1; } inline void init() { for (int i = 0; i < M; i++) { for (int j = 0; j < M; j++) s[i][j] = abs(i - j) <= 2; } } inline friend matrix operator * (const matrix &lhs, const matrix &rhs) { matrix res; long long ans; for (int i = 0; i < M; i++) { for (int j = 0; j < M; j++) { ans = 0; for (int k = 0; k < M; k++) ans += static_cast<long long> (lhs.s[i][k]) * rhs.s[k][j]; res.s[i][j] = ans % mod; } } return res; } #undef M } ans, base; long long n; int main() { scanf("%lld", &n); if (n == 1) { puts("10"); return 0; } base.init(); for (int i = 1; i < 10; i++) ans.s[0][i] = 1; for (n--; n; n >>= 1, base = base * base) if (n & 1) ans = ans * base; int res = 0; for (int i = 0; i < 10; i++) up(res, ans.s[0][i]); printf("%d\n", res); return 0; }