zoukankan      html  css  js  c++  java
  • 【u206】最大赢家

    Time Limit: 1 second
    Memory Limit: 128 MB

    【问题描述】

    Nic和Susan在玩一个有趣的游戏:在游戏开始前,他们先约定一个正整数n,同时令m=1。游戏过程中,每个人都可以将m的值扩大2到9中的 
    任意倍数。第一个使得m≥n的人就是最后的赢家。 
    假设Nic和Susan都十分聪明,并且游戏过程中都使用最佳的策略,问谁会是最后的赢家(Nic总是第一个先玩)。 


    【输入格式】

    一个正整数n(1≤n≤2^32-1)。

    【输出格式】

    在使用最佳的策略的情况下,如果Nic必胜,则输出“Nic”。如果Susan必胜,则输出“Susan”。否则输出“God”。

    【数据规模】

    Sample Input1

    9
    
    
    
    
    
    
    
    
    

    Sample Output1

    Nic
    
    【题解】
    等价题意如下
    给定N,Nic和Susan轮流将N整除2~9,第1个使N<=1的人赢。
    Nic先手,问对于给定的N谁必胜。谁必胜
    设f[n]表示N为n时是先手赢还是先手输。
    转移
    假设x ∈{2,3,4,5,6,7,8,9};
    如果n/x为整数。则M=n/x否则M= (n / x)+1 这里的除法是整除运算。直接去尾。
    然后f[n] = f[n] || !f[M];
    我们这里的讲解围绕那个等价题意展开。
    F[1..9]都为true表示Nic只要除一下就能<=1了。所以是先手赢。
    然后我们对F[t]考虑。
    如果f[t/x](这里的x∈上面那个区间)是先手输。也就是说先手从t/x开始会输。
    那么我们只要让t/x变成t就好了,然后就变成先手赢了。
    因为你是t。然后除一个x就变成t/x了。然后先手就不是nic了。而是Susan.而f[t/x]==true表示在t/x时先手(这下变成Susan)一定会输。那不就等价为f[t]是先手(nic)赢了吗?
    根据这样的规律我们可以写出以下程序
    (注意:下面这个程序不足以过所有的数据);
    memset(bo, false, sizeof(bo));
    for (int i = 1; i <= 9; i++)
    {
    bo[i] = true;
    }
    for (int i = 10; i <= 21999999; i++)
    for (int j = 2; j <= 9; j++)
    {
    int mm;
    if ((i %j) == 0)
    mm = i / j;
    else
    mm = (i / j) + 1;
    if (!bo[mm])
    bo[i] = true;
    }
    然后我们用这个程序求出bo[1..2000]的值。进而可以发现规律
    —n =[1, 9],先手必胜
    —n =[10, 18],先手必败即后手必胜
    —n =[19, 162],先手必胜
    —n =[163, 324],先手必败即后手必胜
    也就是先手胜i = 9 if (n<=9) 先手
    后手胜i=i*2 if (n <=i) 后手
    先手胜i=i*9 if (n <=i) 先手
    后手胜i=i*2 if (n <= i)后手
    i会很大 ,要用long long
    。。。
    【代码】
    /*
    等价题意如下
    给定N,Nic和Susan轮流将N整除2~9,第1个使N<=1的人赢。
    Nic先手,问对于给定的N谁必胜。
    
    */
    #include <cstdio>
    
    long long n;
    
    int main()
    {
    	scanf("%lld", &n);
    	long long i = 9; //一开始i == 9然后小于9就是先手胜
    	int b = 1;
    	while (b != 2) //这个条件是不可能实现的 。所以就一直循环。
    	{
    		if (n <= i) //如果在我们找到的规律区间里就输出相应的答案 然后结束循环
    		{
    			if (b == 1)
    				printf("Nic
    ");
    			else
    				printf("Susan
    ");
    			break;
    		}
    		if (b == 1) //如果现在是先手胜的区间那么就直接*2
    			i = i * 2;
    		else //否则乘9;
    			i = i * 9;
    		b = 1 - b;
    	}
    	return 0;
    }


  • 相关阅读:
    C#异常小知识
    Cisco路由器配置学习-ip accounting
    Sublime Text 3预览Markdown
    什么是permit-inside功能
    锐捷双出口
    思科双出口+策略路由+NAT
    github常见操作和常见错误
    网易注册页面知识点
    java,xml等注释删除,正则表达式使用123
    简单多线程是否安全判断
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7632327.html
Copyright © 2011-2022 走看看