针对CSP-J/S的每日一练:Day7

文章讨论如何利用哈希表和前缀和优化算法解决游戏角色在升级时寻找替换装备的问题。

一、审题

题目描述

在某个游戏里,玩家可以给自己的角色穿上各种装备,每件装备都有自己的品质和属性。角色的属性可以通过穿戴的装备进行累加得到。

游戏中有 nnn 种装备,编号从1到 nnn,每件装备有一个品质 qiq_iqi 和三个属性值 aia_iaibib_ibicic_ici。一件装备的属性可以简单地看做是其品质 qiq_iqi 与三个属性 aia_iaibib_ibicic_ici 的乘积,即 pi=qi×ai×bi×cip_i=q_i\times a_i\times b_i\times c_ipi=qi×ai×bi×ci

一位玩家的角色已经穿戴了 mmm 件装备,其中第 iii 件装备的编号为 pip_ipi。角色的属性值可以分别表示为 A=∑i=1maiA=\sum_{i=1}^m a_iA=i=1maiB=∑i=1mbiB=\sum_{i=1}^m b_iB=i=1mbi 以及 C=∑i=1mciC=\sum_{i=1}^m c_iC=i=1mci

现在,角色想要升级,需要找到一个品质值 QQQ 最小的装备进行替换,即找到编号 jjj 使得 qj<Qq_j<Qqj<Qpj>aj×bj×cjp_j>a_j\times b_j\times c_jpj>aj×bj×cj。如果存在多个符合要求的装备,那么应该选择编号最小的一个进行替换。

请你编写程序,求出符合要求的装备编号 jjj

输入格式

第一行两个整数 nnnmmm,分别表示装备总数和玩家装备数。

接下来 nnn 行,每行描述一个装备。其中第 iii 行包含四个整数 qiq_iqiaia_iaibib_ibicic_ici,分别表示第 iii 件装备的品质和三个属性值。

接下来 mmm 行,每行描述一件已经穿戴的装备。其中第 iii 行包含一个整数 pip_ipi,表示该装备的编号。

输出格式

输出一个整数,表示符合要求的装备编号 jjj。如果不存在任何一件符合要求的装备,输出-1。

样例输入

5 2
2 1 2 3
3 1 1 1
1 2 4 5
4 6 7 1
5 1 1 2
2
4

样例输出

3

数据说明

对于50%的评测用例,1≤n≤1001\leq n\leq 1001n1001≤m≤501\leq m\leq 501m50

对于100%的评测用例,1≤n≤1061\leq n\leq10^61n1061≤m≤1051\leq m\leq 10^51m1051≤qi≤1041\leq q_i\leq 10^41qi1041≤ai,bi,ci≤1001\leq a_i,b_i,c_i\leq 1001ai,bi,ci1001≤pi≤1091\leq p_i\leq 10^91pi109

提示

对于50%的数据,可以直接暴力枚举符合条件的装备,然后选择品质最小的一个。时间复杂度为 O(nm)O(nm)O(nm)

对于100%的数据,可以使用哈希表维护已经穿戴的装备编号,然后对于每个品质小于当前穿戴装备品质的装备,计算其属性值,如果符合要求则更新答案。同时,可以使用前缀和优化存储和计算属性值。时间复杂度为 O(n)O(n)O(n)

题目来源:CSP-J 2020年模拟赛试题

二、思路

步骤一:读懂题目并理解要求

首先,需要读懂题目并理解其中的问题:通过一种数据结构算法,找到符合要求的一件装备,从而求得其编号。在本题中,找到符合要求的装备需要满足两个条件:品质 qjq_jqj 小于指定值 QQQ,同时其属性 pjp_jpj 大于 aj×bj×cja_j \times b_j \times c_jaj×bj×cj。其中,pj=qj×aj×bj×cjp_j=q_j\times a_j \times b_j \times c_jpj=qj×aj×bj×cj

步骤二:确定算法

对于这道题目,最直接想到的方法是遍历所有可能的装备,找到符合要求的装备。但是这样的时间复杂度是 O(nm)O(nm)O(nm),即使 nnnmmm 比较小也会超时。因此我们需要更加高效的算法解决此问题。

在本题中,我们可以通过哈希表存储已经穿戴的装备编号,然后对于每个品质小于当前穿戴装备品质的装备,计算其属性值,如果符合要求则更新答案。同时,可以使用前缀和优化存储和计算属性值。由于哈希表的查找时间是常数级别的,因此时间复杂度是 O(n)O(n)O(n),可以通过此题。

步骤三:实现代码

在确定好算法之后,我们就可以实现代码来解决本题。需要注意以下几点:

  • 首先需要使用哈希表存储已经穿戴的装备编号,即将 mmm 个编号存储到哈希表中。
  • 接着循环遍历 nnn 种装备,找到符合条件的装备并更新答案。同时,可以使用前缀和优化存储和计算属性值。
  • 最后输出答案即可。

三、参考代码

#include <iostream>
using namespace std;

int main()
{
    // 读入数据
    int n, m, Q;
    cin >> n >> m >> Q;
    int q[m], a[m], b[m], c[m];
    for (int i = 0; i < m; i++)
    {
        cin >> q[i] >> a[i] >> b[i] >> c[i];
    }
    // 处理数据
    int ans = -1;
    int has_worn[m+1] = {0}; // 哈希表记录已穿戴的装备
    for (int i = 1; i <= n; i++)
    {
        int qq, aa, bb, cc;
        cin >> qq >> aa >> bb >> cc;
        int p = qq * aa * bb * cc; // 计算当前装备的属性值
        for (int j = 0; j < m; j++)
        {
            if (q[j] < qq && !has_worn[j+1] && p > a[j] * b[j] * c[j]) {
                ans = j + 1;
                a[j] = b[j] = c[j] = 0; // 将已穿戴的装备清空
            }
        }
        // 更新已穿戴的装备编号
        if (qq <= Q)
        {
            has_worn[ans] = 1;
        }
    }
    
    // 输出答案
    cout << ans;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值