题解:B4159 [BCSP-X 2024 12 月小学高年级组] 打怪升级
Charles_with_wkc · · 题解
小序
我一开始写这题的时候以为答案一定递增结果看了样例瞬间无语。
前置知识
DP。
思路
考虑两种情况。
- 回血,就是用当前的血量去掉
b_{i,j} 然后加上a_i 。 - 修改等级,枚举等级然后用当前的血量去掉
b_{i,j} 。
考虑本题应该是动态规划。
- 定义,
dp_{i,j} 表示在第i 关的时候主角等级为j 的最大血量。 - 初始化,定义在第
0 关等级为1 ,主角血量为m 。 - 转移,在上方已经说过了,只需要融入动态规划,在这里需要注意,如果打不过那么就不可以转移。
代码
#include<bits/stdc++.h> using namespace std; #define endl '\n' #define int long long const int N=1505; int a[N],b[N][N],dp[N][N]; /* dp[i][j]:在第i关的时候主角等级为j的最大血量 */ int n,m; signed main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++){ for(int j=1;j<=i;j++){ cin>>b[i][j]; } } dp[0][1]=m; for(int i=1;i<=n;i++){ for(int j=1;j<=i;j++){ if(dp[i-1][j]-b[i][j]<=0) continue;//打不过 dp[i][j]=max(dp[i][j],dp[i-1][j]-b[i][j]+a[i]); for(int k=1;k<=j+1;k++){ dp[i][k]=max(dp[i][k],dp[i-1][j]-b[i][j]); } } } for(int i=1;i<=n;i++){ int ans=0; for(int j=i+1;j>=1;j--){ if(dp[i][j]>0){ ans=j; break; } } cout<<ans<<endl; } return 0; }