【2024年华为杯广东工业大学程序设计竞赛 】 C,B题

C:取糖果 https://ac.nowcoder.com/acm/contest/79664/C
题意:
Alice和Bob正在玩一个游戏,游戏规则如下:
一共有m种糖果,现在有m堆从1到n编号的糖果堆,每堆糖果中有若干个类型可能不同的糖果。Alice和Bob轮流操作,每次操作选定一个区间[l,r]和糖果类型x,然后对于编号在[l,r]内的所有糖果堆,将类型为x的糖果全部拿走(必须满足这些糖果堆里每个糖果堆至少有一个类型为x的糖果)。最后无糖果可取的一方将输掉游戏。
Alice和Bob都很想获胜,他们都会在每一步中使用最优的操作。现在Aice先手,请问谁将赢得这场游戏?

分析:这个题目属于博弈论中的Nim游戏,在这个糖果游戏中,每次操作都是选择一个区间[l, r]和一个糖果类型x,然后从每个编号在[l, r]内的糖果堆中拿走所有类型为x的糖果。这个规则意味着,一个糖果类型的总数会受到每次操作的影响,而每个单独糖果堆的具体内容则不那么重要。

我们可以将这个游戏与Nim游戏进行类比。在Nim游戏中,每堆石子的数量是关键,而它们的位置是不重要的。玩家的目标是通过取走最后一颗石子来赢得游戏。如果我们将每种类型的糖果视为一堆石子,那么每次操作就相当于在Nim游戏中从一堆石子中取走一些石子。


完整代码:

#include<iostream>
using namespace std;

int main(){
    int n,m;cin >> n >> m;
    int ans = 0;
    int c[1005];
    for(int i = 1; i<= n;i++){
        int x;cin >> x;
        for(int j = 1; j<= x;j++){
            int t;cin >> t;
            c[t]++;
        }
    }
    for(int i =1; i<=m;i++){
        ans ^= c[i];
    }
    if(ans){
        cout << "Alice" << endl;
    }else cout << "Bob" << endl;
}


B:你是银狼 https://ac.nowcoder.com/acm/contest/79664/B
题意:
一排房间,编号i范围[0,n],你一开始在0号房间,你只能从i号房间走到i+1号房间。
你有生存值属性,初始生存值为M,生存值不能小于0。
房间分为挑战房间、奖励房间和事件房间。在挑战房间,你可以选择挑战里面的怪物,挑战怪物会消耗生存值 a i a_i ai;在奖励房间,你可以获得 a i a_i ai,点生存值。领取奖励和桃战怪物视为通关这个房间。同时,存在事件房间,这些房间被黑塔设置了安全限制,因此你无法跳过这个房间,必须通关这个房间,必须消耗 a i a_i ai生存值。同时你可以选择不挑战或不接受奖励而直接走到下一个房间(视为没有通关这个房间)。最多只能损失 S 点生存值。走出 n 号房间即完成骇入;问最多通过几个房间?

分析:我们可以贪心的想,对于前i个房间,当遇到挑战房间但如果挑战将导致生存值小于0或总生存值损失超过S时,玩家会从优先队列中取出之前挑战中消耗生存值最大的房间,并尝试回退这个消耗。这样做的目的是释放一些生存值,从而可以挑战当前的房间。这是一种局部最优的选择,因为它保留了继续游戏的可能性,而不是立即导致失败。
跟牛客小白月赛中小A的任务有点类似https://ac.nowcoder.com/acm/contest/78306/E


完整代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e6 + 10;
ll n,m,s;
int a[N],b[N];
priority_queue<int> q;
signed main(){
    cin >> n >> m >> s;
    for(int i = 1; i<=n;i++) cin >> a[i];
    for(int i = 1; i<= n;i++) cin >> b[i];
    int now = 0;
    int ans = 0;
    for(int i = 1; i<= n;i++){
        if(b[i] == 1){
            if(m-a[i]>=0&&s-a[i]>=0){
                now++;
                q.push(a[i]);
                m-=a[i];s-=a[i];
            }else{
                m-=a[i];s-=a[i];
                q.push(a[i]);
                m+=q.top();s+=q.top();
                q.pop();
            }
        }else if(b[i] == 2){
            m += a[i];
            now++;
        }else{
          now++;
            while(!q.empty()){
                if(m-a[i]>=0&&s-a[i]>=0)break;
                m+=q.top();s+=q.top();
                q.pop();
                now--;
            }
            if(m-a[i]<0||s-a[i]<0)break;
            m-=a[i];s-=a[i];
        }
        ans = max(ans,now);
    }
    cout << ans << endl;
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值