// 请把代码粘贴在这里#include <iostream>
#include <vector>
#include <cstring> // 用于 memset
using namespace std;
const int MOD = 1000000007;
// 题目范围:n,m <= 50, k <= 12, 价值 <= 12
// 状态:x, y, 已拿数量cnt, 当前最大价值max_val(0表示没拿过, 1-13表示价值1-13)
long long memo[55][55][15][15];
int grid[55][55];
int n, m, k;
/*
@param x 当前横坐标
@param y 当前纵坐标
@param cnt 当前已拿宝物数量
@param max_val_idx 当前手中宝物最大价值的索引 (0表示-1/没拿, 1对应价值0, ..., 13对应价值12)
@return 从当前状态到达终点的合法方案数
*/
long long dfs(int x, int y, int cnt, int max_val_idx) {
// 1. 越界检查
if (x >= n || y >= m) return 0;
// 2. 到达终点
if (x == n - 1 && y == m - 1) {
long long res = 0;
int current_val = grid[x][y];
int prev_max_val = (max_val_idx == 0) ? -1 : (max_val_idx - 1);
// 情况A:不拿终点的宝物
if (cnt == k) {
res = (res + 1) % MOD;
}
// 情况B:拿终点的宝物 (需满足数量+1=k 且 价值严格大于之前最大值)
if (cnt + 1 == k && current_val > prev_max_val) {
res = (res + 1) % MOD;
}
return res;
}
// 3. 记忆化检查 (如果算过,直接返回)
if (memo[x][y][cnt][max_val_idx] != -1) {
return memo[x][y][cnt][max_val_idx];
}
// 4. 继续搜索
long long ans = 0;
int current_val = grid[x][y];
int prev_max_val = (max_val_idx == 0) ? -1 : (max_val_idx - 1);
// 方向:向下 (x+1, y) 和 向右 (x, y+1)
// 选择1:不拿当前格子的宝物,直接往下走
ans = (ans + dfs(x + 1, y, cnt, max_val_idx)) % MOD;
ans = (ans + dfs(x, y + 1, cnt, max_val_idx)) % MOD;
// 选择2:拿当前格子的宝物 (如果符合条件),然后往下走
if (current_val > prev_max_val && cnt < k) {
// 更新最大价值索引:真实价值 + 1
int new_max_val_idx = current_val + 1;
ans = (ans + dfs(x + 1, y, cnt + 1, new_max_val_idx)) % MOD;
ans = (ans + dfs(x, y + 1, cnt + 1, new_max_val_idx)) % MOD;
}
// 5. 记录结果并返回
memo[x][y][cnt][max_val_idx] = ans;
return ans;
}
int main() {
// 优化输入输出速度
ios_base::sync_with_stdio(false);
cin.tie(NULL);
if (!(cin >> n >> m >> k)) return 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> grid[i][j];
}
}
// 初始化 memo 为 -1,表示未计算
memset(memo, -1, sizeof(memo));
// 从 (0,0) 开始,初始数量0,初始最大价值索引0 (代表-1)
cout << dfs(0, 0, 0, 0) << endl;
return 0;
}
0 回复
0 转发
0 喜欢
3 阅读



