RoboCom-2021复赛-冒险者分队

冒险者分队是人气 MMORPG《最终幻想 14》里的一个游戏系统。玩家通过招募 NPC (非玩家角色)组成小队完成特定任务后可以获取丰厚的奖励。

由于完成任务有能力的要求,因此我们需要对 NPC 进行一定的训练。NPC 组成的小队会有三个属性:体能、心智,以及战术,玩家可以选择以下的两种训练课程之一对小队进行训练:

  • 提升其中一个属性 40,降低其他两个属性各 20;
  • 提升其中两个属性 20,降低剩下一个属性 40。

如果在选择的训练课程后有任意一个属性小于 0,那么训练会失败,属性不会发生变化。

为了完成特定任务,现在给定小队的初始属性和目标属性,请回答是否有可能通过一定的训练,使得小队的属性正好达到目标属性的值,如果可以的话,最少的次数是多少?

输入格式:

输入第一行是一个正整数 T (≤105),表示有多少组询问。

接下来的 T 组询问,每组询问有两行,每行三个非负整数,第一行为小队初始的属性,第二行为需要达成的目标属性。

所有属性值均大于等于 0,小于等于 2×109。

输出格式:

如果目标属性无法通过训练达到,输出一行 −1,否则输出一个整数,表示达到目标属性的最少训练次数。

输入样例:

4
25 30 35
65 10 15
100 200 300
200 180 220
100 100 100
0 0 0
777 888 999
777 888 999

输出样例:

1
3
-1
0

一、题意理解

        归结为数学问题,用目标值减去初始值,得到差值,考虑如何用给出的变化方式构造差值。同时考虑非法情况。

二、官方解题思路&&批注

        1.不妨考虑两种训练的属性值的变化特征,不难发现都是 20 的倍数,所以可以将操作简化为:

* 一个属性 +2,两个属性 -1;

* 一个属性 -2,两个属性 +1。

恰好,无论是 +2、-1,还是 -2、+1,对 3 取模时结果都一致,因此操作无法改变属性值差的取模结果,这是判定可行性的重要标准之一。

另外,由于训练的属性变化总和均为 0,因此属性值的和也不应该发生变化。也就是说,差值的和应该为 0。(注意-2%3=-2)

综上,我们先确定什么情况有可行解:

1. 显然差值必须是 20 的倍数

2. 第一条满足的情况下,除以 20,对 3 取模答案相同

3. 第二条满足的情况下,差值的和为 0

        2、在解决可行解的问题后,我们需要解决最小训练次数的问题。

        假设三个属性的差值分别为 a1, a2, a3,除去直接得到答案的 a1=a2=a3=0,因为差值和为 0,所以一定至少有一个正数以及一个负数,并且可以通过全部取负值的方式得到两个负数以及一个正数。不妨假设有 a1 < a2 < 0 < a3。(因为操作取负对称,所以不改变结果)

        我们的目标显然是让 a1、a2以及a3等于0。我们首先考虑让a3尽快变成0,这样的话可以利用 (+1, +1, -2) 的操作先进行操作,但由于 a3 = -(a1 + a2),因此在 a3 变成 0 的过程中,a2 会先变成 0,这时有 a3 = -a1。我们此时再使用 (+2, -1, -1) 以及 (+1, +1, -2) 的两步操作,组合出 (+3, 0, -3) 的操作,完成剩下的调整。

        不难看到如果只使用 (+1, +1, -2) 以及 (+3, 0, -3) 两种操作的话,这样做的答案是最小的。如何证明这两个操作能构造出最优解,交给有兴趣的同学证明。(贪心)

三、代码&&思路

1.按照3条判断非法状态

2.处理成x <y < 0 <z

3.y先会变成0——res+=-y,更新x z;

4.res += z / 3 * 2;——通过(3,-3) 让x z变成0

  

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <math.h>
#include <map>
#include <set>
#include <queue>

using namespace std;
#define endl '\n'
void solve(){
    int a,b,c,x,y,z;
    cin >> a >> b >> c >> x >> y >> z;
    int dx = a - x,dy = b - y,dz = c - z;//处理差值
    if (dx % 20 || dy % 20 || dz % 20 || a + b + c != x + y + z)//1.1 不是20的倍数return
    {
        cout << -1 << endl;
        return;
    }
    dx /= 20,dy /= 20,dz /= 20;
    int mod = (dx % 3 + 3) % 3;
    if ((dy % 3 + 3) % 3 != mod || (dz % 3 + 3) % 3 % 3 != mod)//1.2 mod3不为1 return
    {
        cout << -1 << endl;
        return;
    }
    int num = 0;
    num += (dx > 0) + (dy > 0) + (dz > 0);
    if (num == 2) dx = -dx,dy = -dy,dz = -dz;// 转化为标准形式
    x = min({dx,dy,dz}),z = max({dx,dy,dz}),y = dx + dy + dz - x - z;//排序

    int res = 0;
    res += -y,x -= y,z += y * 2,y = 0;//2.1 通过+1让y变成0,更新x z 
    res += z / 3 * 2;//2.2 通过(3,-3) 让x z变成0
    cout << res << endl;
}
signed main(){
    std::ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int t;
    cin >> t;
    while (t--) solve();
}

四、总结

1.在非法判断条件中:“除以 20,对 3 取模答案相同”,这一条比较难想,可以积累

2.本质上是数学问题,不要畏惧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
根据提供的引用内容,CSP-J2021复赛有两道题目,分别是分糖果和小熊的果篮。 对于第一题分糖果,题目来源是CCF,难度为入门。根据给出的代码,这是一个基于循环的算法,通过遍历[l,r]区间内的数,计算数对n取模后的最大值。具体的实现细节可以参考引用中的代码。这道题目属于入门级别,比较简单。 第二题是关于小熊的果篮。给定一个长度为n的数组a,其中连续的相同元素被视为一个块,要求按照块的顺序输出每个块的头元素,并删除已输出的元素。具体的实现细节可以参考引用中的代码。这道题目需要使用双链表来处理,时间复杂度为O(n)。 综上所述,CSP-J2021复赛的题目包括分糖果和小熊的果篮,具体的解题思路和代码实现可以参考上述引用内容。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [[CSP-J 2021]比赛题解](https://blog.csdn.net/weixin_56550385/article/details/126811201)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [新鲜出炉的 CSP-J 2021 复赛题目 题解](https://blog.csdn.net/qq_23109971/article/details/121024436)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Blossom๑.๑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值