洛谷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;
}
View Code

 

posted @ 2020-02-04 20:34  朝暮不思  阅读(175)  评论(0编辑  收藏  举报