zoukankan      html  css  js  c++  java
  • AcWing 229. 新NIM游戏 (线性基+博弈论)打卡

    题目:https://www.acwing.com/problem/content/description/231/

    题意:给出n堆石子,然后第一回合,A玩家可以随便拿多少堆石子,第二回合B玩家随便拿多少堆石子,第三回合开始就按照NIM博弈来进行,问第一个玩家是否可以获胜,获胜第一回合可以拿最少的火柴数是多少

    思路:首先我们清楚的知道NIM博弈,获胜条件是   所有石子异或起来不能为0,也就是说第二个玩家只要能找到当前某堆石子能被其他堆石子表示出来,然后把其他不是的全部拿走就好了,所以我们第一个玩家

    必须只能保留基底,其他的都不能留,这样第二个玩家就不能找到被其他表示,因为这是一个极大不相关组,要求拿走的火柴最少,也就是我们用来建基底的要更多,就从大到小排序,

    1,这里回答一个疑问,为什么我们一定要把除去基底之外的所有拿走,不能留下一个,然后把能表示出他的基底拿走呢,因为我们基底是按位运算保存的.能表示出当前数,也就是说明存在这个数的二进制位异或出来的,但是这是由若干数异或出来的,可能因为要表示的数没有这个二进制位.但是他异或了两次这个位才取消掉,所以这样的做法拿的火柴数必定比直接拿走的多

    #include<bits/stdc++.h>
    #define maxn 100005
    #define mod 1000000007
    using namespace std;
    typedef long long ll;
    ll a[maxn],ins[maxn];
    ll k,sum;
    int cmp(ll x,ll y){
        return x>y;
    }
    void gauss(){
        for(int i=1;i<=k;i++){
            ll x=a[i];
            for(int j=63;j>=0;j--){
                if((a[i]>>j)&1){
                    if(!ins[j]){
                        ins[j]=a[i];
                        sum-=x;
                        break;
                    }
                    else{
                         a[i]^=ins[j];
                    }
                }
            }
        }
        printf("%lld",sum);
    }
    int main(){
        scanf("%lld",&k);
        for(int i=1;i<=k;i++){
          scanf("%lld",&a[i]);
          sum+=a[i];
        }
        sort(a+1,a+k+1,cmp);
        gauss(); 
    }
  • 相关阅读:
    Dialog 不能全屏,左右有间距解决方案
    mac apktool配置
    HTML5网站如何做到完全不需要jQuery
    js中控制小数点的显示位数的技术整理
    ASP.NET后台获取cookie中文乱码解决办法
    javascript删除元素节点
    js获取不到动态添加的标签的值的解决方法
    JS常用方法函数整理
    JS获取当前页面的URL信息
    轻轻松松 用U盘安装WIN7
  • 原文地址:https://www.cnblogs.com/Lis-/p/11295944.html
Copyright © 2011-2022 走看看