zoukankan      html  css  js  c++  java
  • 【取火柴游戏】

    非常玄妙的博弈入门

    好神仙的题啊

    其实这就是经典的(Nim)问题

    如果所有石子的异或和为(0),那么这就是一个必败状态

    这个我只会感性理解一下

    首先所有的石子都是(0),异或和肯定是(0),这也自然是一个必败状态

    而如果异或和不是(0),我们设异或和为(X)

    我们可以找到这个(X)的最高位,显然那些石子堆里至少有一个这一位上也是(1)的,设这一个石子堆是(x_i)

    那么就有

    [x_1⊕x_2⊕x_3⊕...⊕x_i⊕...x_n=X ]

    那么显然

    [x_1⊕x_2⊕x_3⊕...⊕x_i⊕...x_n⊕X=0 ]

    根据异或的结合律

    [x_1⊕x_2⊕...⊕(x_i⊕X)⊕...x_n=0 ]

    也就是说原来的(x_i)变成(x_i⊕X)就好了,也就是要取走(x_i-x_i⊕X),这样就可以使得下一步变成必败状态

    由于我们取走的一定得是正数,所以得满足(x_i-x_i⊕X>0)

    但是如果(X=0)的话,(x_i⊕X=x_i),所以(x_i-x_i⊕X=0),取走的是(0),并不满足游戏规则

    所以一大波分析下来突然就觉得好有道理

    代码

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define re register
    #define maxn 500005
    #define lowbit(x) ((x)&(-x))
    inline int read()
    {
    	char c=getchar();
    	int x=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9')
    		x=(x<<3)+(x<<1)+c-48,c=getchar();
    	return x;
    }
    int n,a[maxn];
    int ans,t;
    int main()
    {
    	n=read();
    	for(re int i=1;i<=n;i++) a[i]=read(),ans^=a[i];
    	t=ans;
    	if(!ans)
    	{
    		puts("lose");
    		return 0;
    	}
    	for(re int i=1;i<=n;i++)
    	{
    		if(a[i]-(a[i]^ans)>0)
    		{
    			printf("%d %d",a[i]-(a[i]^t),i);
    			putchar(10);
    			a[i]=(a[i]^t);
    			break;
    		}
    	}
    	for(re int i=1;i<=n;i++)
    		printf("%d ",a[i]);
    	return 0;
    }
    
  • 相关阅读:
    重构该何时登场
    重构
    中国剩余定理
    连分数的应用
    连分数的性质
    有限连分数与欧几里德除法的联系
    连分数
    费马大定理
    P4178 Tree 点分治
    LOJ 6029. 「雅礼集训 2017 Day1」市场
  • 原文地址:https://www.cnblogs.com/asuldb/p/10207933.html
Copyright © 2011-2022 走看看