《P1544 三倍经验》
题目描述
数字金字塔由 n 行整数组成,第 i(1≤i≤n) 行有 i 个数字,一个示例如下。
73 98 1 02 7 4 4
4 5 2 6 5
现在你在金字塔的顶部(第一行),你希望走到金字塔的底部(第 n 行),每一步你只能走向当前所在位置的左下方的数字或者右下方的数字。同时作为一个强大的小朋友,你可以选择金字塔中的不多于 k 个数字让他们成为原来的 3 倍。
你会收集你路上经过的所有位置上的数字,最后的得分即为收集的数字之和,求最大得分。
输入格式
第一行输入两个整数 n,k,表示数字金字塔的行数和乘 3 的数字个数最大值;
接下来 n 行,其中的第 i 行有 i 个以空格隔开的整数依次表示数字金字塔第 i 行的数字 ai,1,ai,2,ai,3...ai,i。
输出格式
一行一个整数,表示最大得分。
输入输出样例
输入 #1复制
5 3 7 3 9 8 1 0 2 7 4 4 4 5 2 6 5
输出 #1复制
75
说明/提示
对于 30% 的数据,满足 k≤n≤6,并且对于任意 1≤i≤n,1≤j≤i 满足 0≤ai,j≤100;
对于 100% 的数据,满足 1≤n≤100,0≤k≤2n(n+1),且对于任意 1≤i≤n,1≤j≤i 满足 ∣ai,j∣≤109。
代码实现:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 105;
int f[N][N][N*N/2], v[N][N]; // f替代dp,v替代a(表示值value)
int n, m; // m替代k
signed main() {
cin >> n >> m;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= i; j++)
cin >> v[i][j];
memset(f, -0x3f, sizeof f);
f[1][1][0] = v[1][1];
f[1][1][1] = v[1][1] * 3;
for(int i = 2; i <= n; i++)
for(int j = 1; j <= i; j++) {
// 不使用三倍加成的情况
for(int l = 0; l <= min(m, i); l++)
f[i][j][l] = max(f[i-1][j][l], f[i-1][j-1][l]) + v[i][j];
// 使用三倍加成的情况
for(int l = 1; l <= min(m, i); l++)
f[i][j][l] = max(f[i][j][l], max(f[i-1][j][l-1], f[i-1][j-1][l-1]) + v[i][j] * 3);
}
int res = -1e18; // res替代ans(表示结果result)
for(int i = 1; i <= n; i++)
for(int j = 0; j <= m; j++)
res = max(res, f[n][i][j]);
cout << res;
return 0;
}