Description
小卤蛋刚把dnf的技能点重新洗了一遍,现在他要重新加点,假设他的技能树一共有n层,第i层有n-i+1个
技能,每个技能只能够学习一次。除了第1层的技能可以直接学习外,其他技能学习都要学习前置技能,
即你要学习第i(i>=2)层第j列的技能,那么你要先学习第i-1层的第j列和第j+1列的技能。每个技能学习
后都会获得一定的战力加成。
现在小卤蛋有m个技能点,一个技能点可以学习一个技能,他想知道加完点后他可以获得的最大战力加成为多少。
Solution
可以想象一下,对于一个点,如果能加点,那么如下图,以他为顶点往下延伸得到的直角三角形上所有点都需要加点
那么我们可以从右上角开始枚举,然后做dp,令
- 表示第i列第j行时剩下k点可加的最优答案
有状态转移方程 ;
其中 表示上一行可以转移的点
Code
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e5 + 5; const int mod = 9973; int a[55][55]; ll dp[55][55][1305]; int num[55]; int main() { int n, m; while(cin >> n >> m) { memset(dp, 0, sizeof(dp)); for(int i = 1; i <= n; i++) { num[i] = num[i - 1] + i; for(int j = 1; j <= n - i + 1; j++) { cin >> a[i][j]; a[i][j] += a[i - 1][j]; } } ll ans = 0; for(int i = n; i >= 1; i--) { for(int j = 0; j <= n - i + 1; j++) { for(int k = num[j]; k <= m; k++) { for(int l = max(0, j - 1); l < n - i + 1; l++) { dp[i][j][k] = max(dp[i][j][k], dp[i + 1][l][k - j] + a[j][i]); } ans = max(ans, dp[i][j][m]); } } } cout << ans << "\n"; } return 0; }