码迷,mamicode.com
首页 > 其他好文 > 详细

sdut——4541:小志志和小峰峰的日常(取石子博弈模板题 4合1)

时间:2019-08-21 21:50:14      阅读:100      评论:0      收藏:0      [点我收藏+]

标签:空格   经典的   bsp   break   有趣   数据   经典   ace   efi   

小志志和小峰峰的日常

Time Limit: 1000 ms Memory Limit: 65536 KiB

Problem Description

小志志和小峰峰特别喜欢一起讨论一些很好玩的问题。 
小志志发现一个有趣的游戏,马上和小峰峰进行了分享。 
有 n 堆石子堆,每堆石子个数为 a[i]。 
到小志志的回合:小志志可以选取其中的一堆,拿至少 1 个最多 x 个石子。 
到小峰峰的回合:小峰峰可以选取其中的一堆,拿至少 1 个最多 y 个石子。 
小志志先手,回合交替进行,到该玩家回合如果无法操作,该玩家输。 
 

Input

输入一个 T,总共有 T 组测试数据。 
每组测试数据: 
第一行输入 n 代表有 n 堆石子堆。 
第二行输入 n 堆石子堆分别的数量。 
第三行输入两个用空格隔开的 x, y 分别代表小志志和小峰峰对于一堆石子最多能拿的数量。 
(1 <= n <= 1e5, 1 <= a[i], x, y <= 1e9)

Output

小志志赢输出 “xzz”,小峰峰赢输出 “xff”,答案不包含 “”。

Sample Input

3 
1 
3 
2 2 
2 
4 7 
4 5 
3 
3 4 7 
8 8

Sample Output

xff 
xzz 
xff


题解:

我们需要分类讨论:
x == y 的时候:经典的 sg
x != y 的时候:
任意的 a[i] <= min(x, y):Nim 博弈
否则至少存在一堆 a[i] > min(x, y):
如果 x > y:
我们把先手能拿的石子个数看成 y 的话,就是经典的 sg,如果亦或和不是 0 那么先手必
胜。
如果亦或和是 0,那么先手可以选择石子个数大于 y 的堆,拿掉 y+1 的石子个数。这样对
于对方而言亦或和还是 0。所以先手必胜。
所以无论如何:先手必胜
如果 x < y:
如果石子堆个数 > min(x, y) 的堆数大于 2:后手必胜,先手无论如何处理都会变成上述的
情况。
如果石子堆个数 > min(x, y) 的堆数 == 1:
先手肯定会选择 > min(x, y) 的石子堆进行操作,不然先手必败。
设这堆石子个数为 t,除去这堆石子的亦或和为 ans,你只有将这堆石子个数变成 ans &&
ans <= x 才能赢。
所以 t-x <= ans && ans <= x 先手必胜。
否则先手必败。

 

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+5;
string s[2];
ll n, x, y, T;
ll arr[N];

bool f1(ll ans){
    for(int i = 1; i <= n; i++)
    ans ^= arr[i]%(x+1);
    return ans != 0;
}

int main()
{
    s[1] = "xzz", s[0] = "xff";
    cin >> T;
    while(T--)
    {
        cin >> n;
        for(int i = 1; i <= n; i++) cin >> arr[i];
        cin >> x >> y;
        if(x == y) cout << s[f1(0)] << endl; //经典sg
        else{
            int flag = 0, ans = 0;
            for(int i = 1; i <= n; i++){
                ans ^= arr[i];
                if(arr[i] > min(x, y))
                    flag++;
            }
            if(!flag){  // Nim博弈
                if(ans) cout << s[1] << endl;
                else cout << s[0] << endl;
            }
            else{
                if(x > y) cout << s[1] << endl;
                else{
                    if(flag > 1) cout << s[0] << endl;
                    else{
                        int t;
                        for(int i = 1; i <= n; i++){
                            if(arr[i] > min(x, y)){
                                t = arr[i];
                                ans ^= arr[i];
                                break;
                            }
                        }
                        if(t - ans <= x && ans <= x)
                            cout << s[1] << endl;
                        else cout << s[0] << endl;
                    }
                }
            }
        }
    }
    return 0;
}

 



sdut——4541:小志志和小峰峰的日常(取石子博弈模板题 4合1)

标签:空格   经典的   bsp   break   有趣   数据   经典   ace   efi   

原文地址:https://www.cnblogs.com/philo-zhou/p/11391233.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!