G58_2 尼姆(Nim)游戏*【博弈SG】Nim取石子游戏3[P1247微改]
该比赛已结束,您无法在比赛模式下递交该题目。您可以点击“在题库中打开”以普通模式查看和递交本题。
Description
【题目描述】有一种有趣的 $2$ 人游戏:
一开始有 $N$ 堆石子(每堆石子的数量分别为 $a_i$),参与游戏双方轮流取石子;每人每次只能在其中一堆石子中取走若干颗石子(最少取 $1$ 颗)。石子取光,则游戏结束。取完石子的一方为胜。
假如参与游戏的玩家都非常聪明,问最后谁会获胜?
【输入格式】
多组测试数据,每组测试数据描述如下:
第一行一个整数 $N$($1 \le N \le 10^4$)。
第二行 $N$ 个整数 $a_i$($1 \le a_i \le 2^{30}$)。
【输出格式】
对于每组测试数据:
若先手必败,则输出 $First Lose$。
若先手必胜则输出 $First Win$ ,并且输出在游戏第一轮,先手可能采取的所有策略 $x \ y$ :表示先手从第 $x$ 堆石子中取走 $y$ 个石子。 每种策略占一行,按字典序依次输出。
【样例输入】
4
7 9 12 15
2
6 6
【样例输出】
First Win
2 5
3 11
4 13
First Lose
Hint
G58 尼姆(Nim)游戏【博弈论】scy教学版:
#include<bits/stdc++.h> using namespace std;
int a[11000],n,ans; int d[35]; int f[35],b[35],len; int main() { // freopen("nim.in","r",stdin); freopen("nim.out","w",stdout); d[1]=1; for(int i=2;i<=31;i++) d[i]=d[i-1]*2;//d[i]表示2^(i-1),也就是二进制从右到左的第i位的十进制值
while(scanf("%d",&n)!=EOF)
{
ans=0;
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
ans^=a[i];
for(int j=1;j<=31;j++)
if( a[i]&d[j] ) f[j]++;
}
if(ans==0) printf("First Lose\n");
else
{
printf("First Win\n");
len=0;for(int i=1;i<=31;i++) if( f[i]%2==1)b[++len]=i;//b数组存储全局的矛盾位
for(int i=1;i<=n;i++)
{
int w=31; while( (d[w]&a[i])==0 ) w--;
if(w<b[len]) continue;//表示第i堆石头无法一步改变全局为平衡状态
int s=0;
for(int j=1;j<=len;j++)
{
if(a[i]& d[ b[j] ])
s=s+ d[ b[j] ];
else
s=s- d[ b[j] ];
}
if(s<=a[i]&&s>0) printf("%d %d\n",i,s);
}
}
}
return 0;
}</pre>