洛谷1437 敲砖块

洛谷1437 敲砖块


原题链接


交题记录

N/A 考试题。。。


题解

先来观察一下性质。

1 1 1
 2 2
  3 

由这个和样例很容易想到这样存储:

1 1 1
2 2
3

即“左对齐”存储。
状态就是\(f[k][i][j]\),表示只在(i,j)和(i,j)上方打最大的收入。
然而并不好转移
的确不好转移。。。。。
呵呵呵
可以无视上面
但如果这样存呢

1
1 2
1 2 3

可以理解为“斜过来”,即:

.//
//
/

再把斜线组成的行看做新行。
现在下面变成了左边。
所以设\(f[i][j][k]\),在第\(i\)行取前\(j\)个,且一共取了\(k\)个的最大收入
\(f[i][j][k]=max{f[i-1][l][k-j]+s[i][j]}(l=j-1..i-1)\)
即枚举选几个。
注意特判l


Code

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
typedef long long ll;
il int gi(){
    rg int x=0,f=1;rg char ch=getchar();
    while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,m,v[51][51],s[51][51],ss[51],ans=0;
int f[51][51][501];
int main(){
//     #define Fname "brike"
    // freopen(Fname".in","r",stdin);
    // freopen(Fname".out","w",stdout);
    n=gi(),m=gi();
    rep(j,1,n)drep(i,n,j)v[i][j]=gi();
    rep(i,1,n)rep(j,1,i)s[i][j]=v[i][j]+s[i][j-1];
    memset(f,-1,sizeof f);
    f[0][0][0]=0;
    rep(i,1,n)rep(j,0,i){
        rep(k,j,m)rep(l,max(0,j-1),i-1)
            if(f[i-1][l][k-j]+1)f[i][j][k]=max(f[i][j][k],f[i-1][l][k-j]+s[i][j]);
        ans=max(ans,f[i][j][m]);
    }
    printf("%d\n",ans);
    return 0;
}

【代码wa了一个点,有人看出来请指正】

posted @ 2017-08-28 00:16  菜狗xzz  阅读(163)  评论(0编辑  收藏  举报