有一個\(base(2 \leq base \leq 6)\)進制系統,這裏面的數都是整數,不含前導0,相鄰兩個數字不相同。
並且每一個數字有一個得分\(score(1 \leq score \leq 10^9)\),得分爲 相鄰兩個數字之差的平方之和。ide
給出\(base\)和\(score\),求知足條件的整數的個數 \(mod \, 2^{32}\)。優化
設\(dp(i, j)\)表示知足當前分數爲\(i\)最後一個數字是\(j\)的數字的個數。
遞推就是枚舉下一個數字\(k\),就有轉移方程:
\(dp(i+d,k)=\sum dp(i, j)\),其中\(k \neq j\)且\(d=(k-j)^2\)。
這種方法的複雜度使\(O(base^2 \cdot score)\)的。spa
由於狀態轉移中,能獲得的最大分數是\((base-1)^2\),因此咱們的轉移矩陣只要保留前面\((base-1)^2\)個\(score\)的信息就好了。
用語言不方便表達,我舉具體例子,
當\(base=3\)時,有以下轉移:
上面9行很好理解,就是一個錯位。
下面3行纔是狀態的轉移。
容易看出,咱們的矩陣的邊長最大會達到\(6(6-1)^2=150\)。code
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef unsigned int LL; const int maxn = 150; int n, m, sz; struct Matrix { LL a[maxn][maxn]; Matrix() { for(int i = 0; i < maxn; i++) for(int j = 0; j < maxn; j++) a[i][j] = 0; } Matrix operator * (const Matrix& t) const { Matrix ans; for(int i = 0; i < sz; i++) for(int j = 0; j < sz; j++) if(a[i][j]) for(int k = 0; k < sz; k++) ans.a[i][k] += a[i][j] * t.a[j][k]; return ans; } }; Matrix pow_mod(Matrix a, int n) { Matrix ans; for(int i = 0; i < sz; i++) ans.a[i][i] = 1; while(n) { if(n & 1) ans = ans * a; a = a * a; n >>= 1; } return ans; } LL a[maxn], dp[25][6]; int main() { int T; scanf("%d", &T); for(int kase = 1; kase <= T; kase++) { printf("Case %d: ", kase); scanf("%d%d", &n, &m); int N = (n - 1) * (n - 1) * n; //DP memset(dp, 0, sizeof(dp)); for(int i = 1; i < n; i++) dp[0][i] = 1; for(int i = 0; i < (n - 1) * (n - 1); i++) { for(int j = 0; j < n; j++) { for(int k = 0; k < n; k++) { int d = (k - j) * (k - j); if(!d || i + d > (n - 1) * (n - 1)) continue; dp[i + d][k] += dp[i][j]; } } } if(m < (n - 1) * (n - 1)) { LL ans = 0; for(int i = 0; i < n; i++) ans += dp[m][i]; printf("%u\n", ans); continue; } sz = N; int s = (n - 1) * (n - 1); for(int i = 0; i < (n - 1) * (n - 1); i++) for(int j = 0; j < n; j++) a[i * n + j] = dp[i][j]; Matrix M; for(int i = n; i < N; i++) M.a[i - n][i] = 1; for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) if(j != i) { int d = (j - i) * (j - i); M.a[N - n + i][n * (s - d) + j] = 1; } M = pow_mod(M, m - (n - 1) * (n - 1) + 1); LL ans = 0; for(int i = N - n; i < N; i++) for(int j = 0; j < N; j++) ans += M.a[i][j] * a[j]; printf("%u\n", ans); } return 0; }