题目描述
X 国王有一个地宫宝库,是 n×m 个格子的矩阵,每个格子放一件宝贝,每个宝贝贴着价值标签。
地宫的入口在左上角,出口在右下角。
小明被带到地宫的入口,国王要求他只能向右或向下行走。
走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。
当小明走到出口时,如果他手中的宝贝恰好是 k 件,则这些宝贝就可以送给小明。
请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这 k 件宝贝。
输入格式
第一行 3 个整数,n,m,k,含义见题目描述。
接下来 n 行,每行有 m 个整数 Ci 用来描述宝库矩阵每个格子的宝贝价值。
输出格式
输出一个整数,表示正好取 k 个宝贝的行动方案数。
该数字可能很大,输出它对 1000000007 取模的结果。
数据范围
1≤n,m≤50,
1≤k≤12,
0≤Ci≤12
样例
输入样例1:
2 2 2
1 2
2 1
输出样例1:
2
输入样例2:
2 3 2
1 2 3
2 1 5
输出样例2:
14
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <climits>
#include <cstdio>
#define MOD 1000000007
using namespace std;
int main(){
int dp[60][60][20][20] = {0}; // (0,1)坐标 2允许拿几个 3允许拿的最大价值
int in[60][60], n, m, k, i, j, x, y, z, ans = 0;
cin >>n >>m >>k;
for(i = 1; i <= n; i++)
for(j = 1; j <= m; j++){
cin >>in[i][j];
in[i][j]++; // 允许拿0个的时候,最大价值为0,所以格子的价值从1开始
}
dp[1][1][0][0] = 1; // 第一格初始化,不拿
dp[1][1][1][in[1][1]] = 1; // 第一格初始化,拿
for(i = 1; i <= n; i++){
for(j = 1; j <= m; j++){
for(x = 0; x <= k; x++){
for(y = 0; y <= 13; y++){
int &val = dp[i][j][x][y];
// 不拿
val = (val+ dp[i-1][j][x][y])%MOD; // 从上面下来
val = (val+ dp[i][j-1][x][y])%MOD; // 从左边过来
// 拿,并且要允许拿,而且允许拿的最大价值要==本格的价值
if(x > 0 && y == in[i][j]){
for(z = 0; z < y; z++){
val = (val+ dp[i-1][j][x-1][z])%MOD;
val = (val+ dp[i][j-1][x-1][z])%MOD;
}
}
}
}
}
}
// 拿了k个的所有价值的路径都需要加起来
for(i = 0; i <= 13; i++) ans = (ans+dp[n][m][k][i])%MOD;
cout <<ans;
return 0;
}