【LOJ】#2067. 「SDOI2016」硬币游戏

题解

c一样的就是一个独立的游戏

我们对于2和3的指数
sg[i][j] 表示(c cdot 2^i cdot 3^j)的棋子,只有这个硬币是反面,翻转的硬币是正面的sg值

枚举sg函数所有可能的局面,每个后继局面的sg值,就是所有被翻到背面的硬币sg值的异或和

我们忽略了反转当前硬币前面可能不是全部正面,但是这是正确的,我们可以证明一下

如果一个局面所有背面朝上的棋子sg函数异或起来为(x)
(x!=0)
那么我们找到(x)最高位是(2^k),我们找到一个含有(2^k)的硬币(a_n)(x^a_n < a_n) 我们选择这个棋子的后继局面中等于(x^a_n)的那个即可将局面的sg异或值变成0

(x = 0)
如果一个局面行动后的后继局面中有0,那么这个局面的值一定不为0
所有可操作的局面sg的值都不为0,且后继局面中的值与该局面sg值不等
故而无论如何操作,sg值为正

代码

#include <bits/stdc++.h>
#define enter putchar('
')
#define space putchar(' ')
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define MAXN 1000005
#define mo 999999137
#define pb push_back
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;T f = 1;char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        res = res * 10 + c - '0';
        c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) out(x / 10);
    putchar('0' + x % 10);
}
int sg[55][55];
bool f[60005];
int N,MAXQ,a[30005];
void Init() {
    memset(sg,0,sizeof(sg));
    sg[0][0] = 0;
    for(int i = 0 ; i <= 50 ; ++i) {
        for(int j = 0 ; j <= 50 ; ++j) {
            if(i == 0 && j == 0) continue;
            memset(f,0,sizeof(f));
            if(i != 0) {
                for(int p = 1 ; p <= i ; ++p) {
                    int t = 0;
                    for(int q = 1 ; q <= min(MAXQ,i / p) ; ++q) {
                        t ^= sg[i - p * q][j];
                        f[t] = 1;
                    }
                }
            }
            if(j != 0) {
                for(int p = 1 ; p <= j ; ++p) {
                    int t = 0;
                    for(int q = 1 ; q <= min(MAXQ,j / p) ; ++q) {
                        t ^= sg[i][j - p * q];
                        f[t] = 1;
                    }
                }
            }
            int p = 0;
            while(f[p]) ++p;
            sg[i][j] = p;
        }
    }
}
void Solve() {
    read(N);read(MAXQ);
    Init();
    int ans = 0;
    for(int i = 1 ; i <= N ; ++i) {
        read(a[i]);
        if(!a[i]) {
            int t = i,c2 = 0,c3 = 0;
            while(t % 2 == 0) t /= 2,++c2;
            while(t % 3 == 0) t /= 3,++c3;
            ans ^= sg[c2][c3];
        }
    }
    if(!ans) puts("lose");
    else puts("win");
}
int main() {
    int T;
    read(T);
    while(T--) {
        Solve();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ivorysi/p/9523454.html