洛谷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
",ans);
return 0;
}
【代码wa了一个点,有人看出来请指正】