首页 > 其他分享 >[题解] [洛谷 P1174] 打砖块

[题解] [洛谷 P1174] 打砖块

时间:2024-04-20 18:00:59浏览次数:19  
标签:分数 洛谷 int 题解 子弹 P1174 MAXN 一列 砖块

[洛谷 P1174] 打砖块

题目描述

有 \(n\) 行 \(m\) 列的砖块和 \(k\) 发子弹,每个砖块都有一个得分,每次可以用一发子弹打碎某一列最下面的砖块并得到相应的得分。有的砖块在打碎后可以获得一发额外子弹的奖励。求该游戏的最大得分。

image

输入格式

第一行有 \(3\)个正整数, \(n,m,k\) 。表示开始的时候,有 \(n\) 行 \(m\) 列的砖块,小红有 \(k\) 发子弹。

接下来有 \(n\) 行,每行的格式如下:

\(f_1 c_1 f_2 c_2 f_3 c_3 ... f_m c_m\)

其中 \(f_i\) 为正整数,表示这一行的第 \(i\) 列的砖,在打碎以后的得分。\(c_i\) 为一个字符,只有两种可能,Y 或者 N。Y 表示有一发奖励的子弹,N 表示没有。

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

输出格式

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

题解

不难看出该题需要使用动态规划解决。设计状态 \(dp_{i,j}\) 表示前i列,用j颗子弹能够得到的最高分数。使用前缀和 \(sum_{i,j}\) 表示打掉第 \(i\) 行第 \(j\) 列能够得到的分数。此时不难得出状态转移方程: \(dp_{i,j} = max(dp[i - 1][j - l] + sum[i][l])\) 其中, \(l\) 为枚举的在当前列的花费。显然,这种做法在不会出现 Y 时可以应对,但在出现 Y 时就会有以下问题:对于其中一列,假设是如下情况:

1 Y
1 N

那么在打掉下面的 N 后,如果我们还剩下一颗子弹,就可以没有花费打掉 Y ,但如果我们在打完 N 后刚好用完了所有子弹,那么我们就无法再获得 Y 的分数。此外还有如下特殊情况:

1 N 1 Y
1 N 1 N

这种情况下,对于第二列,我们虽然可以以一颗子弹的花费获得两个砖块的分数,但是我们需要用到两颗子弹。因此,我们需要考虑最后一颗子弹是否在这一列打完。如果最后一颗子弹在这一列打完,我们就无法通过“借用”子弹的方式获得 Y 的分数,否则我们就可以无花费的打掉 Y 。特别的,如果我们在当前列花费的子弹数小于总子弹数,那么我们一定可以无花费的打掉 Y 。

因此,我们需要记录两种状态:\(dp1_{i,j}\) 表示最后一颗子弹打在这一列的最高分数, \(dp2_{i,j}\) 表示最后一颗子弹没有打在这一列的分数。相应的,我们每个方块的得分也需要分成最后一颗子弹打在这一列时每个砖块的得分 \(sum1_{i,j}\) 和最后一颗子弹没有打在这一列时每个砖块的得分 \(sum2_{i, j}\) 。同时对两个状态进行转移即可。

AC代码

#include <algorithm>
#include <iostream>
#define int long long
using namespace std;

const int MAXN = 1003;

int f[MAXN][MAXN];
char c[MAXN][MAXN];

int dp1[MAXN][MAXN]; //dp_i,j: 考虑前i列,花费j颗子弹,最后一颗子弹打在这一列的最高分数
int dp2[MAXN][MAXN]; //dp_i,j: 考虑前i列,花费j颗子弹,最后一颗子弹不打在这一列的最高分数
int sum1[MAXN][MAXN], sum2[MAXN][MAXN]; // sum:分数的前缀和

int n, m, k;
signed main() {
    // 数据输入
    cin >> n >> m >> k;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            cin >> f[i][j] >> c[i][j];
        }
    }
    // 初始化sum
    for (int i = 1; i <= m; i++) {
        int cnt = 0;
        for (int j = n; j > 0; j--) {
            if (c[j][i] == 'Y') {
                sum1[i][cnt] += f[j][i]; // 这一列可以预支
            } else {
                cnt++;
                sum1[i][cnt] = sum2[i][cnt] = sum1[i][cnt - 1] + f[j][i];
            }
        }
    }
    // dp
    for (int j = 1; j <= m; j++) { // 列数
        for (int i = 0; i <= k; i++) { // 消耗的总子弹数
            for (int l = 0; l <= min(n, i); l++) { // 在当前列消耗的子弹数
                dp1[j][i] = max(dp1[j][i], dp1[j - 1][i - l] + sum1[j][l]); // 如果当前这一列不是最后打到的,就可以无脑预支
                if (l != 0) dp2[j][i] = max(dp2[j][i], dp1[j - 1][i - l] + sum2[j][l]); // 不预支的情况
                if (l < i) dp2[j][i] = max(dp2[j][i], dp2[j - 1][i - l] + sum1[j][l]); // 一定可以预支的情况
            }
        }
    }
    cout << dp2[m][k] << '\n';
    return 0;
}

标签:分数,洛谷,int,题解,子弹,P1174,MAXN,一列,砖块
From: https://www.cnblogs.com/wxy3265/p/18147953

相关文章

  • [题解] [洛谷 P1174] 打砖块
    [洛谷P1174]打砖块题目描述有\(n\)行\(m\)列的砖块和\(k\)发子弹,每个砖块都有一个得分,每次可以用一发子弹打碎某一列最下面的砖块并得到相应的得分。有的砖块在打碎后可以获得一发额外子弹的奖励。求该游戏的最大得分。输入格式第一行有\(3\)个正整数,\(n,m,k\)。......
  • newstartweek3部分题解
    64位利用格式化字符串修改got表例题:newstartweek3putorsystem老规矩先checksec和代码审计:看到开了canary和NX(但是对于这道题的话canary是没有用的),然后源码这边也没有发现有system函数,也没有后门函数,所以我们需要自己在libc里面找,然后就有bin/sh那么我们就只用把got表里......
  • 洛谷 P1204 [USACO1.2] 挤牛奶Milking Cows
    题意:给定n个区间,左端点和右端点表示工作开始时间和结束时间。求最长一直有人在工作的时间和无人工作的时间。思路:想到了并查集,还有差分树状数组,最后选择差分数组。左端点加,右端点减,然后一次遍历即可。总结:习惯性的在右端点+1的位置减少了1,但是不适用于这个题目的逻辑。因为在右......
  • [BZOJ3037] 创世纪 题解
    基环内向树上dp,不过在这里提供给一种非典型做法。考虑将环上的每一条边都断开,这样就会形成多棵树,先在这些树上进行树形\(dp\)。设\(dp_{i,0/1}\)表示不选/选\(i\)时,\(i\)子树内的最大选点数。明显方程为:\[\begin{cases}dp_{u,0}=\sum\limits_{v\inuson}\max(dp_{v,0},dp......
  • [题解]ABC209F Deforestation
    ABC209FDeforestation首先我们可以思考\(a_i\)和\(a_{i+1}\)先砍哪棵花费少。可以看出,当\(a[i]<a[i+1]\)时,先砍\(a[i+1]\),反之亦然。所以这个题转化成了:给定\(n-1\)个关系,分别表示\(n\)个值中相邻两个的大小关系,问满足这些关系的序列个数。与AtcoderEducationalDPContest......
  • φ(* ̄0 ̄)3337. poj1845 sumdiv题解
    遇到数论题就要推式子!提供最美丽的latex\[a^b=p_1^{a_1*b}*p_2^{a_2*b}*p_3^{a_3*b}......*p_n^{a_n*b}\\那么他的因数之和为:\\({p_1}^0+{p_1}^1+...+{p_1}^{a_1*b})\\*({p_2}^0+{p_2}^1+...+{p_2}^{a_2*b})\\...\\*({p_n}^0+{p_n}^1+...+{p_n}^{a_n*b})\\=>利用等......
  • 「NOIP2012」同余方程 题解!!
    嗨嗨嗨!又是我想写这道题,我们就需要掌握:拓展欧几里得顾名思义,它就是欧几里得算法(人话:辗转相除法)的proMax版本别告诉我你不会辗转相除法拓展欧几里得的作用是求对于方程\[a*x+b*y=gcd(a,b)\]解出x,y的值。让我们一步步分析!贴个辗转相除板子先:voidojld(inta,intb){ i......
  • poj3696 The Luckiest number 题解
    很容易想到,\(n\)个8可以转换为\((10^{n+1}-1)/9*8\)容易你个集贸啊,xzz推10分钟我推了一个上午顺便膜拜xzz然后就是推式子了。。。(悲\[(10^{n+1}-1)/9*8\equiv0\pmodh\\=>{10^{n+1}*8-8\above1pt9}\equiv0\pmodh\\=>10^{n+1}*8-8\equiv0\pmod{9h}\\=>10^{n+1}*8\e......
  • P321. [NOI2002]荒岛野人Savage题解?!!!
    还是我容易(☚xzz说的)想出,x年后i号野人的位置为:\((C_i+P_i*x)\modm\)我们只要让任意方程:\((C_i+P_i*x)\modm=(C_j+P_j*x)\modm\)解小于\(L_i\)或小于\(L_j\)即可推式子!\[(C_i+P_i*x)≡(C_j+P_j*x)\(mod~m)\\⇿x*(P_i-P_j)+y*m=C_j-C_i\]然后就是拓展欧几里得模板了。......
  • 题解:CSP-S2020] 函数调用
    题解:CSP-S2020]函数调用一句话题意:给定一个有初始值的序列,支持如下三种操作:1、单点加2、全局乘3、递归某些操作1、2、3求最终的序列。标签:topsort,动态规划,转化贡献统计(集中贡献),主客翻转关于topsort:部分分里的树结构基本上直接暗示了正解要使用topsort,而且本来函......