牛客练习赛49 E 筱玛爱游戏 (线性基+博弈)

链接:https://ac.nowcoder.com/acm/contest/946/E
来源:牛客网

筱玛爱游戏
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
题目描述
筱玛是一个热爱游戏的好筱玛。最近,筱玛和马爷在玩这样一种游戏:
首先,桌面上一共有
n
n个数。
两个人轮流从桌面上取走一个数,并把这个数放入集合中。
如果在某次操作结束后,集合中存在一个异或和为
0
0的非空子集,那么进行这次操作的人输。
如果全部取完,则最后操作的人赢。
筱玛和马爷都聪明绝顶,他们都会按照最优策略进行游戏。
马爷作为筱玛的爷爷,决定让筱玛选择先手还是后手。
筱玛为了稳操胜券,想提前知道对于当前的游戏,是先手必胜还是后手必胜。
筱玛想考考你,让你帮他解决这个问题。
输入描述:
输入共两行。
第一行一个整数
n
n,表示桌面上一共有n个数字。
第二行读入
n
n个数,表示桌面上每个数的数值。

输出描述:
输出"First"或"Second"(不包括引号)表示先手赢或后手赢。
示例1
输入
复制
3
1 2 3
输出
复制
Second
备注:
对于100%的数据,
n

10
5
n≤105,数值大小

2
61
≤261。

题意:

思路:

子集异或和不为0这恰好是线性基的性质。
那么我们把数组构造一个线性基,算出能插入到线性基里的个数,
如果是基数那么是先手赢,否则是后手赢。

细节见代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ALL(x) (x).begin(), (x).end()
#define rt return
#define dll(x) scanf("%I64d",&x)
#define xll(x) printf("%I64d\n",x)
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define rep(i,x,n) for(int i=x;i
#define pll pair
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<= 0; i--) {
            if (val & (1LL << i)) {
                if (!d[i]) {
                    d[i] = val;
                    return 1;
                }
                val ^= d[i];
            }
        }
        return 0;
    }
    bool query(ll val) { // 查询val这个数是否存在
        for (int i = mx - 1; i >= 0; i--) {
            if (val & (1LL << i)) {
                if (!d[i]) return 0;
                val ^= d[i];
            }
        }
        return 1;
    }
    ll query_max(ll val) {
        ll ret = val;
        for (int i = mx - 1; i >= 0; i--) if ((ret ^ d[i]) > ret) ret ^= d[i];
        return ret;
    }
    ll query_min() {
        for (int i = 0; i < mx; i++) if (d[i]) return d[i];
        return 0;
    }
    void rebuild() {//消元,保存到p数组
        cnt = 0;
        for (int i = 0; i < mx; i++) {
            for (int j = 0; j < i; j ++ )
                if (d[i] & (1LL << j)) d[i] ^= d[j];
        }
        for (int i = 0; i < mx; i++) if (d[i]) p[cnt++] = d[i];
    }
    ll query_kth(ll k) { //使用前需要rebuild
        ll ret = 0;
        if (k >= (1LL << cnt)) return -1;
        for (int i = cnt - 1; i >= 0; i--) if (k & (1LL << i)) ret ^= p[i];
        return ret;
    }
    ll find(ll x) { //找x是第几大的数,需保证x一定在
        ll ret = 0, c = 0;
        for (int i = 0; i < mx; i++) {
            if (d[i]) {
                if (x >> i & 1) ret += (1LL << c);
                c++;
            }
        }
        return ret;
    }
    LB operator+(const LB & _A)const {  //合并
        LB ret = *this;
        for (int i = mx - 1; i >= 0; i--) if (_A.d[i]) ret.add(_A.d[i]);
        return ret;
    }
};
LB base=LB();

int main()
{
    //freopen("D:\common_text\code_stream\in.txt","r",stdin);
    //freopen("D:\common_text\code_stream\out.txt","w",stdout);
    
    gbtb;
    int n;
    cin>>n;
    int ans=0;
    repd(i,1,n)
    {
        ll x;
        cin>>x;
        ans^=base.add(x);
    }
    if(ans)
        cout<<"First"<= '0' && ch <= '9') {
            *p = *p * 10 - ch + '0';
        }
    }
    else {
        *p = ch - '0';
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 + ch - '0';
        }
    }
}


转载于:https://www.cnblogs.com/qieqiemin/p/11144793.html

你可能感兴趣的:(c/c++)