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;
}