CodeForces 603 C.Lieges of Legendre(博弈论)

Description

n n 堆石子,第i堆有 ai a i 个石子,每轮可以有两种操作,第一种是选一堆非空石子取走一个,第二种是对于一个有 2x 2 x 个石子的偶数堆,将其分成 k k x个石子的堆,问谁必胜

Input

第一行两个整数 n,k n , k ,之后输入 n n 个整数ai(1n105,1k,ai109)

Output

输出胜者

Sample Input

2 1
3 4

Sample Output

Kevin

Solution

组合游戏,记 sg[x] s g [ x ] x x 个石子的堆的sg值, A A 为若干非负整数的集合,mex(A)=min(NA)表示不是 A A 集合的自然数最小值

k为偶数,那么有 2x 2 x 个石子的偶数堆用第二种操作会变成偶数个 x x 个石子的堆,这种后继状态的sg值为偶数个 sg[x] s g [ x ] 异或,即为 0 0 ,进而有sg[2x]=mex(0,sg[2x1]),暴力计算得 sg[0,1,2,3,4]=0,1,2,0,1 s g [ 0 , 1 , 2 , 3 , 4 ] = 0 , 1 , 2 , 0 , 1 ,用数学归纳法验证, n2 n ≥ 2 时, sg[2n1]=0,sg[2n]=1 s g [ 2 n − 1 ] = 0 , s g [ 2 n ] = 1

k=2 k = 2 时显然成立结论成立, k=n k = n 时若成立 sg[2k1]=0,sg[2k]=1 s g [ 2 k − 1 ] = 0 , s g [ 2 k ] = 1 ,那么 k=n+1 k = n + 1 时:

sg[2k+1]=mex(sg[2k])=0 s g [ 2 k + 1 ] = m e x ( s g [ 2 k ] ) = 0 sg[2k+2]=mex(0,sg[2k+1])=1 s g [ 2 k + 2 ] = m e x ( 0 , s g [ 2 k + 1 ] ) = 1

故结论成立,进而得到了任意 n n sg

k k 为奇数,那么有sg[2x]=mex(sg[2x1],sg[x]),暴力计算得 sg[0,1,2,3,4,5]=0,1,0,1,2,0 s g [ 0 , 1 , 2 , 3 , 4 , 5 ] = 0 , 1 , 0 , 1 , 2 , 0 ,用数学归纳法验证, n2 n ≥ 2 时, sg[2n]>0,sg[2n+1]=0 s g [ 2 n ] > 0 , s g [ 2 n + 1 ] = 0

k=2 k = 2 时结论显然成立, k=n k = n 时若成立 sg[2k]>0,sg[2k+1]=0 s g [ 2 k ] > 0 , s g [ 2 k + 1 ] = 0 ,那么 k=n+1 k = n + 1 时:

sg[2k+2]=mex(sg[2k+1],sg[k+1])>0(sg[2k+1]=0) s g [ 2 k + 2 ] = m e x ( s g [ 2 k + 1 ] , s g [ k + 1 ] ) > 0 ( s g [ 2 k + 1 ] = 0 ) sg[2k+3]=mex(sg[2k+2])=0 s g [ 2 k + 3 ] = m e x ( s g [ 2 k + 2 ] ) = 0

故结论成立,进而得到所有奇数的 sg s g 值,对于所有的 sg[2x] s g [ 2 x ] ,递归求出 sg[x] s g [ x ] 即可,时间复杂度 O(log2x) O ( l o g 2 x )

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 111111
int n,k,a,f[5];
map<int,int>sg;
int solve(int a)
{
    if(a<5)return  f[a];
    if(a%2)return 0;
    return solve(a/2)==1?2:1;
}
int main()
{
    f[0]=0,f[1]=1,f[2]=0,f[3]=1,f[4]=2;
    scanf("%d%d",&n,&k);
    int ans=0;
    if(k%2==0)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a);
            if(a==2)ans^=2;
            else if(a==1||a>2&&a%2==0)ans^=1;
        }
    }
    else
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a);
            ans^=solve(a);
        }
    }
    printf("%s\n",ans?"Kevin":"Nicky");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值