SPOJ GAME3 9842. Yet Another Fancy Game 博弈

好久没写过题解了....得找回一下原来写题解总结的习惯


题目大意:

就是现在Ivica和Marica两个人在玩一个游戏

初始的时候,有一个数m = 1,现在连个人轮流对m进行改变,每次可以选择将m变为原来的2倍,或者将m加上1,并且不能使改变后的值比n大,谁将m变为n谁就输了

给定n,Ivica先手,假定两个人都足够聪明,问谁一定会获胜

其中n <= 1e15, 每次 test case 的n的个数数小于等于5, 时间限制500ms


大致思路:

首先,谁走到n处谁就输,所以n是N点(必败点), 对于N - 1,一定是P点(必胜点)。

首先有一个明显的结论是如果n是偶数,那么先手一定败,也就是说,1是N点,这个很容易解释,就是1是一个奇数,先手无论采取怎样的操作都将使得齐变成偶数,这样,后手只需要每次都将n变成奇数( + 1)即可,最终先手都会使得m变成n,先手必败。

这个也可以从下面这个方法中分析出来:

首先若n是偶数,那么不难发现[ n / 2, n]之间的数中,奇数都是P点,偶数都是N点,当n / 2是奇数时, [(n / 2 - 1) / 2, (n / 2 - 1)]之间的所有奇数数乘上2一定是[ n / 2, n]中的N点,而加上1一定是N点(偶数)所以 [(n / 2 - 1) / 2, (n / 2 - 1)]之间所有奇数数是P点,所有偶数是N点,(n / 2)是偶数时同理, 依次递推下去,当n是偶数时, 所有偶数是N点,所有奇数是P点,那么1是P点,所以n是偶数时Marica获胜。


当n是奇数时,如果(n + 1) / 2是奇数,(n - 1) / 2是偶数,则由[(n + 1) / 2, n]中所有奇数是N点,所有偶数是P点,那么(n - 1)/2乘上2到达偶数点P点,(n - 1) / 2也是N点, 同样的可以知道[(n - 1)/4 + 1, (n - 1) / 2]中的所有数都是N点,因为他们乘上二一定到达偶数点且属于[ (n + 1) / 2, n],那么[ (n - 1) /. 4 + 1, (n - 1) / 2]中的所有点是N点,而对于(n - 1) / 4, 无论加上1(变成(n - 1)/ 4 + 1)还是乘上2(变成(n - 1) / 2)都是到达N点, 那么(n - 1) / 4是P点, 这样我们可以发现一个问题:

我们可以讲所有大于n的点看成是N点, 这样对于(n + 1) / 2是奇数时可以发现, n的位置和(n - 1) / 4 + 1的位置具有一样的性质,也就是说n和(n - 1) / 4 + 1具有一样的结果。

同样的当(n + 1) / 2是偶数时,(n + 1) / 4和n有一样的性质。


这样每次向下找与n同样的性质的数(变成(n + 1) /4或是变成(n + 3) / 4)如果还是奇数就继续,如果变成了1,说明此时的n对应1是N点,Ivica获胜,如果n变成了偶数,说明1是P点,Marica获胜


代码如下:

Result  :  Accepted     Time  :  10 ms     Memory  :  2662 KB

/*
 * Author: Gatevin
 * Created Time:  2014/11/7 12:30:54
 * File Name: hehe.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

lint n;
int t;

int main()
{
    scanf("%d", &t);
    while(t--)
    {
        //cin>>n;
        scanf("%lld", &n);
        if(n & 1)
        {
            while(n > 2 && (n & 1))
            {
                if(((n + 1)/2) & 1)
                    n = (n + 3) / 4;
                else
                    n = (n + 1) / 4;
            }
            if(n == 1)
            {
                printf("Ivica\n");
                continue;
            }
            printf("Marica\n");
        }
        else
        {
            printf("Marica\n");
            continue;
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值