牛客小白月赛2 E. 是是非非(尼姆博奕)

题目描述

坎为水,险阳失道,渊深不测;离为火,依附团结,光明绚丽。
坎卦:水洊至,习坎;君子以常德行,习教事。一轮明月照水中,只见影儿不见踪,愚夫当财下去取,摸来摸去一场空。
离卦:明两作,离,大人以继明照四方。官人来占主高升,庄农人家产业增,生意买卖利息厚,匠艺占之大亨通。

有一些石子堆,第
img
堆有
img
个石子。你和算卦先生轮流从任一堆中任取若干颗石子(每次只能取自一堆,并且不能不取),取到最后一颗石子的人获胜。

算卦先生来问你,如果你先手,你是否有必胜策略?若是改动其中几个石子堆中石子的数量呢?

输入描述:

第一行两个正整数 ,表示有 个石堆, 次操作。 第二行 个整数,第 个数 表示第 个石堆初始有 个石子。 接下去
行,每行两个正整数 ,表示把第 堆石子的个数修改成 。操作是累计的,也就是说,每次操作是在上一次操作结束后的状态上操作的。

输出描述:

共 q行,输出每次操作之后先手是否有必胜策略。 如果有,输出 ,否则输出 。

示例1

输入

5 4
6 7 3 4 5
1 6
2 1
2 4
5 5

输出

Kan
Kan
Li
Li

思路

尼姆博弈的模型为:有n堆石子,每次从某堆可以取任意多个,这个问题的答案是石子的异或值为0,先手必输。

在这个题中,还增加了修改石子数量的操作,由异或的性质我们知道:

x^x=0
x^0=x

先存储前缀异或,当把第x个石子修改成y的时候,首先用ans^a[x]这样相当于在前缀异或里面取消了这堆石子,再把之后变成的y异或也就是ans^=y,最后再修改石子堆的值。

最后判断ans==0如果相等先手必输

代码

#include <cstdio>
#include <cstring>
#include <cctype>
#include <stdlib.h>
#include <string>
#include <map>
#include <iostream>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long ll;
const int N=1e5+20;
int a[N];
int main()
{
    int n,q,x,y;
    scanf("%d%d",&n,&q);
    int ans=0;
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&a[i]);
        ans^=a[i];
    }
    while(q--)
    {
        scanf("%d%d",&x,&y);
        ans^=a[x];
        ans^=y;
        a[x]=y;
        if(ans==0) puts("Li");
        else puts("Kan");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/riba2534/article/details/80034773