加法和乘法
from https://ac.nowcoder.com/acm/contest/9983/J
时间限制:1s
空间限制:26MB
题目描述:
有一天牛牛和牛妹在做游戏,规则如下:
桌面上摆着n张纸牌,每张纸牌上写着一个正整数,由牛牛先手轮流执行以下操作:
1.如果桌面上只剩一张纸牌,游戏结束,这张纸牌上的数字如果是奇数则牛牛胜利,反之牛妹胜利。
2.当前行动玩家选择两张纸牌,设上面的数字分别为X,Y接下来玩家从加法和乘法中选择一个并应用到这两个数字上,得到结果为Z,接下来将选择的两张纸牌丢弃,并拿一张新的纸牌放到桌面上,在上面写上Z。
假设双方均以最优策略行动,最后谁会赢?
输入格式:
第一行一个正整数n,代表开始的纸牌数。
第二行n个空格分隔的正整数ai代表开始纸牌上的数字。
1≤n≤106
1≤ai≤109
输出格式:
如果牛牛能赢,输出NiuNiu,否则输出NiuMei。
示例1:
输入:
3
233 2333 23333
输出:
NiuMei
示例2:
输入:
4
1 1 1 1
输出:
NiuNiu
简单的博弈论问题,需要想到一些思维。
如果牛牛想赢,那么需要尽可能多的消耗偶数保留奇数;而牛妹想赢,则需要尽可能多的消耗奇数,保留偶数。
注意:后续odd表示奇数,even表示偶数。
牛牛操作优先级:
1.选择一个奇数一个偶数相乘,得到一个奇数 (消耗1个偶数)
2.选择两个偶数,得到一个偶数 (消耗1个偶数)
3.选择两个奇数,得到一个奇数 (消耗1个奇数)
牛妹操作优先级:
1.选择两个奇数,得到一个偶数 (消耗2个奇数,增加一个偶数)
2.选择一个奇数一个偶数,得到偶数 (消耗1个奇数)
3.选择两个偶数,得到一个偶数 (消耗1个偶数)
总之他们都会尽可能多的消耗对方卡牌而保留自己的卡牌。
代码:
#include<iostream>
using namespace std;
int n,odd = 0,even = 0; //分别表示最初纸牌张数,奇数纸牌张数,偶数纸牌张数
int main(){
cin>>n;
for(int i = 1;i <= n;++i){
int m;
cin>>m;
if(m % 2)
++odd; //如果是奇数odd增1
else
++even; //否则even增1
}
for(int i = 1;i < n;++i){ //一共有n张牌,则要选2得1进行n - 1次
if(i % 2){ //牛牛的操作
if(even && odd) //如果偶数和奇数都存在,那么牛牛会将一个偶数和一个奇数相加得到一个奇数
--even;
else if(odd) //如果只有奇数,那么会将两个奇数相乘得到一个奇数
--odd;
else //如果只有偶数,那么只能选择两个偶数,最终不论加乘只能得到一个偶数
--even;
}
else{ //牛妹的操作
if(odd > 2) //如果奇数个数大于2,那么将两个奇数相加得到一个偶数
odd -= 2,++even;
else if(even && odd)//如果有奇数和偶数,那么将一个奇数乘一个偶数得到一个偶数
--odd;
else if(odd) //如果只有奇数,那么将两个奇数相加得到一个偶数
odd -= 2,++even;
else //如果只有偶数,那么只能选择两个偶数,最终不论加乘只能得到一个偶数
--even;
}
}
if(odd) //如果最后剩下的是奇数,那么niuniu胜利
cout<<"NiuNiu";
else //如果最后剩下的是奇数,那么niumei胜利
cout<<"NiuMei";
return 0;
}