Nim ZOJ - 3591 NIM博弈

4 篇文章 0 订阅

题目链接

不贴题面了,题意如下:

给出一段代码,将输入的数据通过这段代码运算之后得到博弈的初始数组(石头数量),你每一次可以取连续的几堆,使Alice(先手)在玩的时候,可以获胜,即取走一部分异或值不为0的石头,即可保证获胜

分析:

看了大佬的题解才知道这个题怎么做,使用全部数字的连续子序列减去异或值为零的连续子序列的数量即可

以下例进行说明,若通过代码运算之后得到的石头数量分别为 1 2 3 2 3 2 1,设num=0,使用num对他们进行连续异或运算,得到的结果如下:

可以看到,num的值出现了相等的情况,以及等于0的情况

我们可以发现,这些相等的num值中间部分的异或值,必然为0(如1和1对应的2^3^2^3=0),以及num值等于零的时候,也是前面一部分的连续异或值为零的。代码如下

#include<iostream>
#include<vector>
#include<set>
#include<cstdlib>
#include<cstdio>
#include<map>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
const long long maxn = 1e5+7;
long long a[maxn] ;
map<long long,long long>ans;
int main()
{
    long long N,t,S,W;
    cin >> t;
    while(t--)
    {
        ans.clear();
        scanf("%lld%lld%lld",&N,&S,&W);
        long long g = S;
        for (long long i=0; i<N; i++)
        {
            a[i] = g;
            if( a[i] == 0 ) { a[i] = g = W; }
            if( g%2 == 0 ) { g = (g/2); }
            else { g = (g/2) ^ W; }
        }
        long long t = 0;
        ans[0]=1;
        for(long long i = 0; i < N; i ++)
        {
            t^=a[i];
            ans[t]++;
            //cout <<a[i] << " t:" << t << " " << ans[t] <<endl;
        }
        map<long long,long long>::iterator it;
        long long Ans = 0;


        for(it = ans.begin(); it != ans.end(); it++)
        {
            Ans += (it->second)*(it->second-1)/2;
            //cout << it->first <<" " << it->second<<endl;
        }
        long long ANS = N*(N+1)/2;
        ANS-=Ans;
        cout << ANS<< endl;
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值