[LUOGU1437] 敲砖块

题目描述

在一个凹槽中放置了 n 层砖块、最上面的一层有n 块砖,从上到下每层依次减少一块砖。每块砖

都有一个分值,敲掉这块砖就能得到相应的分值,如下图所示。

14 15  4  3  23 33 33 76 2 2 13 11 22 23 31

如果你想敲掉第 i 层的第j 块砖的话,若i=1,你可以直接敲掉它;若i>1,则你必须先敲掉第

i-1 层的第j 和第j+1 块砖。

你现在可以敲掉最多 m 块砖,求得分最多能有多少。

输入输出格式

输入格式:

输入文件的第一行为两个正整数 n 和m;接下来n 行,描述这n 层砖块上的分值a[i][j],满足

0≤a[i][j]≤100。

对于 100%的数据,满足1≤n≤50,1≤m≤n*(n+1)/2;

输出格式:

输出文件仅一行为一个正整数,表示被敲掉砖块的最大价值总和。

输入输出样例

输入样例#1: 
4 5
2 2 3 4
8 2 7
2 3
49
输出样例#1: 
19


 
辣鸡到什么都不想写
如果我们设f[i][j][k]表示前i列正在第j行一共打了k次,我们会发现这个设法使有后效性的。
我们在dp的时候是会对后面产生影响的,而我们不可能记录状态(别说要状压);
所以我们要从后往前考虑,设f[i][j][k]表示已经打了后i列,正在第j行,一共打了k次的最大价值;
f[i][j][k] = max(f[i+1][t][k-j] + a[1][i]+...+a[j][i]),后面的那一堆我们可以用前缀和优化;
t的循环从j-1 ~ n-i;因为我们打到地下了,必须要把它之上的全部打通,所以j-1是下限,n-i是上限,
为什么是n-i而不是n-i+1?因为 ... n - (i + 1) + 1...
这也解释了后面的那么多的和是为什么。
然后这道题就抄会了...
 

 
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
inline int read()
{
    int res=0;char ch=getchar();bool fl=0;
    while(!isdigit(ch)){if(ch=='-')fl=1;ch=getchar();}
    while(isdigit(ch)){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
    return fl?-res:res;
}

int n, m, f[51][51][1250]; //从后往前第i列,第j个,打了k次 
int a[51][51];

int main()
{
    n = read(); m = read();
    for (register int i = 1 ; i <= n ; i ++) 
        for (register int j = 1 ; j <= (n - i + 1) ; j ++)
            a[i][j] = read();
    int sum = 0;
    memset(f, -127, sizeof f);
    f[n+1][0][0] = 0;
    for (register int i = n ; i >= 1 ; i --)
    {
        int sum = 0;
        for (register int j = 0 ; j <= n - i + 1 ; j ++)
        {
            sum += a[j][i];
            for (register int k = j ; k <= m ; k ++)
            {
                for (register int t = max(0, j - 1) ; t <= n - i ; t ++)
                {
                    f[i][j][k] = max(f[i][j][k], f[i+1][t][k-j] + sum);
                }
            }
        }
    }
    int ans=0;
    for (register int i = 1 ; i <= n ; i ++)
    {
        for (register int j = 1 ; j <= n - i + 1 ; j ++)
        {
            ans = max(ans, f[i][j][m]);
        }
    }
    cout << ans;
    return 0;
}
 
 

猜你喜欢

转载自www.cnblogs.com/zZh-Brim/p/9269527.html