zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    C语言 递归 汉诺塔问题 最大公约数问题
    程序的健壮性及代码风格
    C程序练习
    专题——条件控制循环 猜数游戏 随机种子
    C语言 分支与循环 递推思想 穷举 流程的转移控制
    C指针 指针和数组 二维数组的指针 指针应用
    C语言实现的排序
    数组查找算法的C语言 实现-----线性查找和二分查找
    图片转成base64 跨域等安全限制及解决方案
    移动开发那些坑之——safari mobile click事件的冒泡bug
  • 原文地址:https://www.cnblogs.com/enceladus-return0/p/9698458.html
Copyright © 2011-2022 走看看