[蓝桥杯][2014年第五届真题]地宫取宝
摘花生+LIS(要取得当前格子的物品,这个物品必须比当前所拥有的物品都大,所以物品的重量严格递增)的结合题。
状态表示:\(f(i,j,k,c)\):当前到达\((i,j)\)位置,已经取了\(k\)件物品,且最后一件物品的重量为\(c\)。
状态转移:\((i,j)\)可以从\((i-1,j)\)抵达,也可以从\((i,j-1)\)抵达,抵达\((i,j)\)后可考虑选或不选当前位置上的物品,选的话则需满足上一件物品的重量严格小于当前物品的重量。
\[f(i,j,k,c)+=f(i,j-1,k,c);
\\
f(i,j,k,c)+=f(i-1,j,k,c);
\\
f(i,j,k,c)+=\sum_{0 \le w < c} f(i,j-1,k-1,w);
\\
f(i,j,k,c)+=\sum_{0 \le w < c} f(i-1,j,k-1,w);
\]
边界:
\[f(1,1,0,0)=1;
\\
f(1,1,1,g[1][1])=1;
\]
注意点
- 由于体积的范围为\(0 \le C_i \le 12\),我们将体积做加一处理,则体积的范围变成\(1 \le C_i \le 13\),这样第四维下标为\(0\)时可表示当前已选物品的最大体积为\(0\),即没有选任何物品,为边界状态。
- 如果不用体积来记录上一件选择的物品而使用下标来记录的话,则需要五维来表示状态,显然用体积更优。
const int N=55;
int g[N][N];
int f[N][N][15][15];
int n,m,k,c;
int main()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>g[i][j],g[i][j]++,c=max(c,g[i][j]);
f[1][1][0][0]=1;
f[1][1][1][g[1][1]]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int u=0;u<=k;u++)
for(int v=0;v<=c;v++)
{
int &fval=f[i][j][u][v];
fval=(fval+f[i-1][j][u][v])%mod;
fval=(fval+f[i][j-1][u][v])%mod;
if(u && v == g[i][j])
{
for(int w=0;w<g[i][j];w++)
{
fval=(fval+f[i-1][j][u-1][w])%mod;
fval=(fval+f[i][j-1][u-1][w])%mod;
}
}
}
int res=0;
for(int i=1;i<=c;i++) res=(res+f[n][m][k][i])%mod;
cout<<res<<endl;
//system("pause");
return 0;
}