nim博弈 Codeforces603C Lieges of Legendre

传送门:点击打开链接

题意:N堆石子,轮流取石子,先取完的胜利。取石子的方法有两种。

1.在某一堆中取1个

2.如果某一堆里的石子个数为偶数(2*x),可以拆成k堆石子,每堆石子x个

思路:对k的奇偶性讨论,然后再打出SG函数表,很容易就能找到规律,再把规律写出来就做完了

#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;

const int MX = 1e5 + 5;

int SG1[MX], SG2[MX], vis[10];

/*这个是打表程序
void presolve() {
    SG1[0] = SG2[0] = 0;
    for(int i = 1; i < MX; i++) {
        memset(vis, 0, sizeof(vis));
        vis[SG1[i] = SG1[i - 1]] = 1;
        if(i % 2 == 0) vis[SG1[i / 2]] = 1;
        for(int j = 0; j < 10; j++) {
            if(!vis[j]) {
                SG1[i] = j;
                break;
            }
        }

        memset(vis, 0, sizeof(vis));
        vis[SG2[i] = SG2[i - 1]] = 1;
        if(i % 2 == 0) vis[0] = 1;
        for(int j = 0; j < 10; j++) {
            if(!vis[j]) {
                SG2[i] = j;
                break;
            }
        }
    }
    for(int i = 1; i <= 100; i++) {
        printf("[%d:%d]\n", i, SG2[i]);
    }
}*/

int s1(int n) {
    if(n & 1) {
        if(n <= 3) return 1;
        else return 0;
    }
    if(n == 2) return 0;
    if(n == 4) return 2;
    int t = s1(n / 2);
    if(t == 1) return 2;
    return 1;
}

int s2(int n) {
    if(n == 1) return 1;
    if(n == 2) return 2;
    if(n & 1) return 0;
    return 1;
}

int main() {
    //presolve();

    int n, k, t; //FIN;
    while(~scanf("%d%d", &n, &k)) {
        int sum = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%d", &t);
            if(k & 1) sum ^= s1(t);
            else sum ^= s2(t);
        }
        if(sum) printf("Kevin\n");
        else printf("Nicky\n");
    }
    return 0;
}


你可能感兴趣的:(nim博弈 Codeforces603C Lieges of Legendre)