1212. 地宫取宝

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

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

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

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

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

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

输入格式

第一行 \(3\) 个整数,\(n,m,k\),含义见题目描述。

接下来 \(n\) 行,每行有 \(m\) 个整数 \(C_i\) 用来描述宝库矩阵每个格子的宝贝价值。

输出格式

输出一个整数,表示正好取 \(k\) 个宝贝的行动方案数。

该数字可能很大,输出它对 \(1000000007\) 取模的结果。

数据范围

\(1≤n,m≤50\),
\(1≤k≤12\),
\(0≤C_i≤12\)

输入样例1:

2 2 2
1 2
2 1

输出样例1:

2

输入样例2:

2 3 2
1 2 3
2 1 5

输出样例2:

14

解题思路

dp

  • 状态表示:\(f[i][j][t][p]\) 表示位于 \((i,j)\) 且有 \(t\) 个宝贝,其中最大价值为 \(p\) 的方案数
  • 状态计算:
    • 不取位置为 \((i,j)\) 的宝贝时,\(f[i][j][t][p]+=f[i-1][j][t][p]+f[i][j-1][t][p]\)
    • 否则,要求 \(p=a[i][j]\),对于 \(v<p\),有 \(f[i][j][t][p]+=f[i-1][j][t-1][v]+f[i][j-1][t-1][v]\)

由于价值可以为 \(0\),所以价值要整体加一,防止影响对方案数的统计

目标状态:\(\sum_{i=0}^{13}f[n][m][k][i]\)

  • 时间复杂度:\(O(14^2nmk)\)

代码

// Problem: 地宫取宝
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/1214/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int mod=1e9+7;
int n,m,k,a[55][55],f[55][55][15][15];
int main()
{
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++)
    	for(int j=1;j<=m;j++)
    	{
    		cin>>a[i][j];
    		a[i][j]++;
    	}
    		
    f[1][1][0][0]=f[1][1][1][a[1][1]]=1;
    for(int i=1;i<=n;i++)
    	for(int j=1;j<=m;j++)
    		for(int t=0;t<=k;t++)
    			for(int p=0;p<=13;p++)
	    		{
	    			if(t>i+j-1)break;
	    			f[i][j][t][p]=(1ll*f[i][j][t][p]+f[i-1][j][t][p]+f[i][j-1][t][p])%mod;
	    			if(t&&p==a[i][j])
	    			{
	    				for(int v=0;v<p;v++)f[i][j][t][p]=(1ll*f[i][j][t][p]+f[i-1][j][t-1][v]+f[i][j-1][t-1][v])%mod;
	    			}
	    		}
    int res=0;
    for(int i=0;i<=13;i++)res=res=(res+f[n][m][k][i])%mod;
    cout<<res;
    return 0;
}
posted @ 2022-02-09 23:14  zyy2001  阅读(23)  评论(0编辑  收藏  举报