洛谷P1437 [HNOI2004]敲砖块
因为上方和右上方都要打掉才能打这个位置,所以从第一行往下枚举不能获得正确答案,因此考虑倒序枚举,从最后一列按行枚举
具体注释看代码
#include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<vector> #include<string> #include<cstring> #include<map> using namespace std; typedef long long ll; const int N=55; int n; int m; int a[N][N]; int f[N][N][N*(N+1)/2+1]; int main(){ cin>>n>>m; memset(f,-0x3f,sizeof f); int i,j,k,l; f[n+1][0][0]=0; //只有这个位置是初始合法转移位置 for(i=1;i<=n;i++) for(j=1;j<=n-i+1;j++) cin>>a[i][j]; for(i=n;i>=1;i--){ //从最后一列往前枚举 int sum=0; for(j=0;j<=n-i+1;j++){ //0代表这一列不打,最多可以打到n-i+1行 sum+=a[j][i]; //前缀和 for(k=j;k<=m;k++){ //至少要从j开始,最多打m个 for(l=max(0,j-1);l<=n-i;l++){ //因为右上方必须要打,所以至少是j-1,最多枚举到前一列的最后一行 f[i][j][k]=max(f[i][j][k],f[i+1][l][k-j]+sum); } } } } int ans=0; for(i=1;i<=n;i++){ for(j=0;j<=n-i+1;j++){ ans=max(ans,f[i][j][m]); } } cout<<ans<<endl; }
没有人不辛苦,只有人不喊疼