[luogu1174]打砖块

lolifamily

注意:子弹没有的时候不能打有奖励的砖块,打有奖励的砖块可以抽象成借子弹。

w1[i][j] 代表在能借子弹的情况下,第𝑖列用了𝑗颗子弹能够达到的最高分数, w2 代表不能借子弹的最高分数。

f1[i][j] 代表能借子弹的情况下,从左往右打了𝑖列用了𝑗颗子弹能够达到的最高分数, f2 代表不借子弹的最高分数。

Problem

题目描述

小红很喜欢玩一个叫打砖块的游戏,这个游戏的规则如下:

在刚开始的时候,有𝑛×𝑚列的砖块,小红有𝑘发子弹。

小红每次可以用一发子弹,打碎某一列当前处于这一列最下面的那块砖,并且得到相应的得分。(如图所示)

1.png

某些砖块在打碎以后,还可能得到一发子弹的奖励。

最后当所有的砖块都打碎了,或者小红没有子弹了,游戏结束。

小红在游戏开始之前,就已经知道每一块砖在打碎以后的得分,并且知道能不能得到一发奖励的子弹。

小红想知道在这次游戏中她可能的最大得分,可是这个问题对于她来说太难了,你能帮帮她吗?

输入格式

第一行有3个正整数,𝑛,𝑚,𝑘。表示开始的时候,有𝑛×𝑚列的砖块,小红有𝑘发子弹。

接下来有𝑛行,每行的格式如下:𝑓1 𝑐1 𝑓2 𝑐2 𝑓3 𝑐3 𝑓𝑚 𝑐𝑚

其中𝑓𝑖为正整数,表示这一行的第𝑖列的砖,在打碎以后的得分。

𝑐𝑖为一个字符,只有两种可能,𝑌或者𝑁𝑌表示有一发奖励的子弹,𝑁表示没有。

所有的数与字符之间用一个空格隔开,行末没有多余的空格。

输出格式

仅一个正整数,表示最大的得分。

输入

3 4 2
9 N 5 N 1 N 8 N
5 N 5 Y 5 N 5 N
6 N 2 N 4 N 3 N

输出

13

说明 / 提示

对于20%的数据,满足1𝑛,𝑚51𝑘10,所有的字符𝑐都为 N

对于50%的数据,满足1𝑛,𝑚2001𝑘200,所有的字符𝑐都为 N

对于100%的数据,满足1𝑛,𝑚2001𝑘200,字符𝑐可能为 Y

对于100%的数据,所有的𝑓值满足1𝑓10000

Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[205][205],w1[205][205],w2[205][205];
int f1[205][205],f2[205][205];
bool re[205][205];
int main(void)
{
int i,j,l,n,m,k,ch,cnt;
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=n;++i)
{
for(j=1;j<=m;++j)
{
scanf("%d",&a[i][j]);
while(ch=getchar())if(ch=='Y'||ch=='N')break;
re[i][j]=ch=='Y';
}
}
for(j=1;j<=m;++j)
{
cnt=n;
while(cnt&&re[cnt][j])
{
w1[j][0]+=a[cnt][j];--cnt;
}
for(i=1;i<=n&&cnt;++i)//打i发子弹
{
w1[j][i]=w2[j][i]=w1[j][i-1]+a[cnt][j];
--cnt;
while(cnt&&re[cnt][j])
{
w1[j][i]+=a[cnt][j];--cnt;
}
}
}
for(i=1;i<=m;++i)//列
{
for(j=0;j<=k;++j)//子弹
{
for(l=0;l<=j;++l)//当前列使用的子弹数
{
f1[i][j]=max(f1[i][j],f1[i-1][j-l]+w1[i][l]);
if(l<j)f2[i][j]=max(f2[i][j],f2[i-1][j-l]+w1[i][l]);
if(l)f2[i][j]=max(f2[i][j],f1[i-1][j-l]+w2[i][l]);
}
}
}
printf("%d\n",f2[m][k]);
return 0;
}