zoukankan      html  css  js  c++  java
  • AtCoder Beginner Contest 172-F

    AtCoder Beginner Contest 172-F - Unfair Nim(nim博弈,二进制构造)

    题意:

    (mathit n)堆石子,每一堆有(A_i)个石头,问最少从第一堆中拿出多少个石子(也不能拿完,即拿出的石子数为([0,A_1-1]))放在第二堆中可以使(mathit n)堆石子的nim博弈后手必赢?

    思路:

    使(mathit n)堆石子的nim博弈后手必赢条件为:

    (A_1oplus A_2oplus A_3oplus dots oplus A_n=0)

    即:

    (A_1oplus A_2= A_3oplus dots oplus A_n)

    设:

    (X= A_3oplus dots oplus A_n)

    (S=A_1+A_2)

    所以此题可以转化为:

    找出两个整数:(a,b,ain[1,A_1-1])

    满足:

    • (a+b=S)

    • (aoplus b=X)

    (mathit b)尽量小,(mathit a)尽量大,

    我们知道(a+b=aoplus b+2*(a&b))

    那么(aoplus b+2*(a&b)=X+2*(a&b)=S)

    (a&b= frac{(S-X)}{2})

    (D=frac{(S-X)}{2})

    如果(D<0 or (D&X)>0)则一定是无解的,

    (mathit a)的最小值就是(mathit D),所以如果(D>A_1)也是无解的。

    接下来可以对每一个二进位进行单独考虑:

    (a,b,D,X)的二进制表示法中第(mathit i)位为(a_i,b_i,D_i,X_i)

    接下来为使得答案 (mathit a)尽可能大,从二进制高位到低位进行遍历,考虑以下四种情况:

    1. (D_i=1,X_i=1),一定被之前(D&x>0)判断了,所以这里不会存在。
    2. (D_i=1,X_i=0),此时一定(a_i=b_i=1)
    3. (D_i=0,X_i=1),此时一定(a_i+b_i=1),为了(mathit a)尽量大,若(a+2^ileq A_1),则令该位为1.
    4. (D_i=0,X_i=0)此时一定(a_i=b_i=0)

    此时判断下是否满足(a>0),即(b<A_1),若为真,答案就是(A_1-a=b)

    否则输出无解。

    代码:

    int n;
    ll a[maxn];
    int main()
    {
    #if DEBUG_Switch
        freopen("C:\code\input.txt", "r", stdin);
    #endif
        //freopen("C:\code\output.txt","r",stdin);
        cin >> n;
        repd(i, 1, n)
        {
            cin >> a[i];
        }
        ll x = 0ll;
        repd(i, 3, n)
        {
            x ^= a[i];
        }
        ll s = a[1] + a[2];
        ll d = s - x;
        if (d < 0 || (d & 1))
        {
            cout << -1 << endl;
        } else
        {
            d /= 2;
            if (d > a[1] || (d & x) > 0)
            {
                cout << -1 << endl;
            } else
            {
                ll aa = d;
                for (int i = 60; i >= 0; --i)
                {
                    if (x & (1ll << i))
                    {
                        if (aa + (1ll << i) <= a[1])
                        {
                            aa += (1ll << i);
                        }
                    }
                }
                if (aa == 0)
                {
                    cout << -1 << endl;
                } else
                {
                    cout << a[1] - aa << endl;
                }
            }
        }
        return 0;
    }
    
    
    
    
    本博客为本人原创,如需转载,请必须声明博客的源地址。 本人博客地址为:www.cnblogs.com/qieqiemin/ 希望所写的文章对您有帮助。
  • 相关阅读:
    Qt5信号与槽新写法
    Qt获取当前时间
    奇妙的enum class,enum struct组合
    vs2010+qt4编译出现error LNK2001: 无法解析的外部符号 "public: virtual struct QMetaObject等错误
    QTreewidget的使用
    Qt各版本,VS插件下载地址
    Qt按钮设置透明
    Qt全局坐标和相对坐标
    QTableWidget
    c++11中thread join和detach的区别
  • 原文地址:https://www.cnblogs.com/qieqiemin/p/13228097.html
Copyright © 2011-2022 走看看