有一个\(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; }