luogu P1437 [HNOI2004]敲砖块

三角形向右对齐后
你想打掉一个砖块,那么你必须打掉右上方的三角形,前缀和维护
若是第i列若是k个,那么它右边的那一列至少选了k-1个
f[i][j][k] 表示从后向前选到第 i 列第j个一共打了k次的分数

// luogu-judger-enable-o2
#include<cstdio>
#include<cstring>
#include<algorithm>
using std::max;
const int maxn = 57;
#define INF 0x7fffffff
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){ if(c=='-')f=-1; c=getchar(); }
    while(c<='9'&&c>='0')x=x*10+c-'0',c=getchar();
    return x*f;
}
int n,m;
int g[maxn][maxn],s[maxn][maxn];
int f[maxn][maxn][2507];
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n-i+1;++j)
            g[i][j]=read();
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n-i+1;++j)
            s[i][j]=s[i][j-1]+g[j][i];
    for(int i=1;i<=n+1;++i)
        for(int j=0;j<=n+1;++j)
            for(int k=0;k<=m;++k)
                f[i][j][k]=-INF;
    f[n+1][0][0]=0;
    int ans=0;
    for(int i=n;i;--i)
        for(int j=0;j<=n-i+1;++j) 
            for(int k=j;k<=m;++k) {
                for(int l=max(0,j-1);l<=n-i;++l) {
                    if(f[i+1][l][k-j]!=-INF)
                        f[i][j][k]=max(f[i][j][k],f[i+1][l][k-j]+s[i][j]);
                }
                ans=max(ans,f[i][j][k]);
            }
    printf("%d\n",ans);
    return 0;
}

posted @ 2018-02-20 14:40  zzzzx  阅读(112)  评论(0编辑  收藏  举报