lightOJ 矩阵题列表: http://lightoj.com/volume_problemcategory.php?user_id=8459&category=Matrix%20Exponentiation
花了1天多的时间,终于把lightOJ 矩阵题 切的只剩一题了, 最后一题只有1人AC,我想了不多不少的时间还是没有什么思路,所以先放一放吧。
先想想sorce很小的情况下如何做这题, 然后把sorce加大,套个矩阵就可以了。
因为dp是二维的,放入矩阵时把二维转变成一维。
我向来不喜欢把矩阵写成一个类,绝大部分人写的代码都是很费时间的,虽然看起来很爽很清楚,不过我熟练自己的写法,light oj基本很多矩阵题都是1A的,没有调试多久,时间也比很多人快。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define LL unsigned int
const int N = 160;
int b, s;
int n, X;
LL A[N][N], ans[N][N], B[N];
void mult(LL a[][N], LL b[][N]) { //矩阵乘法a = a*b
LL c[N][N] = { 0 };
int i, j, k;
for (k = 0; k < n; k++)
for (i = 0; i < n; i++) if (a[i][k])
for (j = 0; j < n; j++)
c[i][j] += a[i][k] * b[k][j];
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
a[i][j] = c[i][j];
}
inline int sqr(int x) {
return x * x;
}
int dp[38][8];
int dfs(int v, int e) { // v为剩余的分数, e为结尾的数字
if (!v)
return 1;
if(~dp[v][e]) return dp[v][e];
dp[v][e] = 0;
int &ret = dp[v][e], i;
for (i = 0; i < b; i++)
if (i != e) if(v >= sqr(i-e))
ret += dfs(v - sqr(i - e), i);
return ret;
}
int main() {
int i, j, k, cas;
scanf("%d", &cas);
for (int ca = 1; ca <= cas; ca++) {
scanf("%d%d", &b, &s);
printf("Case %d: ", ca);
X = (b - 1) * (b - 1);
n = X * b;
if (b == 2) {
puts("1");
continue;
}
memset(dp, -1, sizeof(dp));
LL sum = 0;
if (s <= X) {
for (i = 1; i < b; i++) //注意没有前导零
sum += dfs(s, i);
printf("%u\n", sum);
continue;
}
for (i = 1; i <= X; i++)
for (j = 0; j < b; j++) {
B[(i - 1) * b + j] = dfs(i, j);
//记忆化搜索出 B[]初始状态 分数为1----(b-1)*(b-1), 以0---b结尾
}
s -= X;
//构造单位矩阵A
for (i = 0; i < n; i++)
for (j = 0; j < n; j++) {
ans[i][j] = (i == j);
A[i][j] = 0;
}
for (i = 0; i < n - b; i++)
A[i + b][i] = 1;
for (i = 1; i <= X; i++)
for (j = 0; j < b; j++)
for (k = 0; k < b; k++) if(j != k)
if (sqr(j - k) == X+1-i) {
A[(i-1) * b + k][(X - 1) * b + j]++;
}
// ans = A^s
while (s > 0) {
if (s & 1) mult(ans, A);
mult(A, A);
s >>= 1;
}
for (i = 0; i < n; i++)
for (j = n-b+1; j < n; j++)
sum += B[i] * ans[i][j];
//取出以1-----b结尾的 数值 (题目的没有前导零可以转化成 结尾不为零)
printf("%u\n", sum);
}
return 0;
}