地宫取宝

77 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第35天,点击查看活动详情

[蓝桥杯 2014 省 AB] 地宫取宝

题目描述

X 国王有一个地宫宝库。是 n×mn \times m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。

地宫的入口在左上角,出口在右下角。

小明被带到地宫的入口,国王要求他只能向右或向下行走。

走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。

当小明走到出口时,如果他手中的宝贝恰好是 kk 件,则这些宝贝就可以送给小明。

请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这 kk 件宝贝。

输入格式

输入一行 33 个整数,用空格分开:nnmmk(1n,m50,1k12)k(1 \le n,m \le 50,1 \le k \le 12)

接下来有 nn 行数据,每行有 mm 个整数 Ci(0Ci12)C_i(0 \le C_i \le 12) 代表这个格子上的宝物的价值。

输出格式

要求输出一个整数,表示正好取 kk 个宝贝的行动方案数。该数字可能很大,输出它对 1000000007(109+7)1000000007(10^9+7) 取模的结果。

样例 #1

样例输入 #1

2 2 2
1 2
2 1

样例输出 #1

2

样例 #2

样例输入 #2

2 3 2
1 2 3
2 1 5

样例输出 #2

14

提示

时限 1 秒, 256M。蓝桥杯 2014 年第五届省赛

分析

这题是个难题,是个dp,四维dp分四种情况,向右走,向下走,都不取,和向右向下走都取dp[i][j][k][c]dp[i][j][k][c]表示走到(i,j)(i,j)这个点,取了kk件物品,其中最大的物品价值是cc的方案数。

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#define pb push_back
#define int long long
using namespace std;
const int N=55;
const int mod=1000000007; 
int w[N][N]; 
int n,m,k;
int dp[N][N][15][15];
int t;
signed main(){
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>w[i][j];
			w[i][j]++;
		}
	}
	dp[1][1][1][w[1][1]]=1;
	dp[1][1][0][0]=1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			if(i==1 && j==1) continue;
			for(int k1=0;k1<=k;k1++){
				for(int c=0;c<=13;c++){
					int &res=dp[i][j][k1][c];
					res=(res+dp[i-1][j][k1][c])%mod;
					res=(res+dp[i][j-1][k1][c])%mod;
					int v=w[i][j];
					if(k1>0 && c==w[i][j]){
						for(int u=0;u<c;u++){
							res=(res+dp[i-1][j][k1-1][u])%mod;
							res=(res+dp[i][j-1][k1-1][u])%mod;
						}
					}	
				}
			}
		}
	int ans=0;
	for(int i=0;i<=13;i++){
		ans=(ans+dp[n][m][k][i])%mod;

	}
	cout<<ans<<endl;
	return 0;	
}