9.25考试

T1 取石子游戏

(nim.pas/c/cpp)

【题目描述】

小林和亮亮正在玩一个取石子的游戏。石子一共有 \(n\) 堆,其中第 \(i\) 堆恰好有$ i $粒石子。小林先取,亮亮后取,并且两人依次轮流取石。每一次取石子的人可以选择任意一堆还未被取完的石子,并取走这一堆中任意多粒石子(注意,不能一粒石子也不取,也不能同时在多堆石子中取石)。最终,无石可取的人为败。

小林和亮亮都十分聪明,他们的每次取石都会采取最优策略。在经过多次戏后,小林发现了先手必胜的条件,但他不满足于此,他想知道,在知道石子的堆数$ n$ 后,他第一次取石有多少种方式可以获胜。

【输入格式】

第一行一个整数 \(T\),表示数据组数。接下来$ T \(行每行一个整数\) n$,表示石子的堆数。

【输出格式】

每组数据输出一个整数,表示在两个人都采用最佳策略的情况下,小林第一次取石能够获胜的方式数,如小林必败,则输出 0。

【样例输入】

2

2

3

【样例输出】

1

0

【样例解释】

\(n=2\) 时小林只有一种取胜方式,即取在第二堆石子中取一粒。$n=3 $时小林必败,因此输出 0。

【数据规模】

对于 20%的数据,\(n<=10\)

对于 50%的数据,\(n<=1000\)

对于 90%的数据,\(n<=10^15\)

对于 100%的数据,\(1<=n<=10^1000,1<=T<=1\)

记得异或序列那个题吗。qwq让你求出1--n的连续异或

由Python得出以下规律qwq

1 n % 4=1
n+1 n % 4=2
0 n % 4=3
n n % 4=0

那个题就解决啦。

记得\(Nim\)游戏吗,就是那个贼水的蓝色的模板题。

好像也是把所有的石子数异或起来,看是否为零,则可以判断出先手必胜/必败

那个题也解决了。

那这个题呢,好像和两个题都有着千丝万缕的联系

不是好像,是就是

下面让我们分析一下

当n% 4=3 时,先手必败,答案为 0 。

当n % 4=1 时,在任意编号为奇数的石子堆中取 1 可使异或和变为 0 ,且只有这些方案,于是答案为 (n+1)/2 。

即后手变先手时,面对了一个先手必败的局面。(i^i+1=1)

n % 4=0 或 2 时,为了使异或序列的结果为零。n+1和n的位数一样,设它们的 最高位为 t,n/n+1 的第 t 位为 1 ,为使n/n+1 变为 0 ,必须修改一个第 t 位为 1 的数。显然修改任一第 t 位为 1 的数都可以使 n/n+1变为 0 。答案即为 n 去掉最高位再加 1 。

然后呢,你去看那毒瘤的数据结构QAQ卧槽,\(10^{1000}\),吃屎吧,我TM才不写高精,90分走人

/*我HUI就是饿死*/
/*死外边儿*/
/*在这跳下去*/
/*也不会敲高精去拿那十分*/
/*↓↓↓*/
/*切了T1真好*/

/*极力掩盖我不会高精的事实*/
#include<cmath>
#include<string>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define IL inline
#define R register
using namespace std;
ll n,T,x,y;

inline void read(ll &x){
    int f=1;x=0;char s=getchar();
    while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
    while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}
    x*=f;
}
inline void print(ll x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9)	print(x/10);
    putchar(x%10+'0');
}

int main()
{
    freopen("nim.in","r",stdin);
    freopen("nim.out","w",stdout);
    read(T);
    while(T--){
    	read(n);
    	if(n%4==3){
    		print(0);
    		cout<<endl; 
    		goto chui_zi_most_grass_egg; 
		}
		if(n%4==1){
			print((n+1)/2);
			cout<<endl; 
			goto chui_zi_most_grass_egg;
		}
		if(n%4==2){
			x=n;
			y=1;
			while(y<=x){
				y*=2;
			}
			y /= 2;
			x-=y;
			x++;
			print(x);
			cout<<endl; 
			goto chui_zi_most_grass_egg;
		}
		if(n%4==0){
			x=n;
			y=1;
			
			while(y<=x){
				y*=2;
			}
			y /= 2;
			x-=y;
			x++;
			print(x);
			cout<<endl; 
			goto chui_zi_most_grass_egg;
		}
		chui_zi_most_grass_egg:;
	} 
    return 0;
}
posted @ 2018-09-25 11:03  enceladus  阅读(356)  评论(0编辑  收藏  举报

Contact with me