(博弈/nim)取火柴游戏

给出n堆火柴,两人轮流取,标准nim博弈
要求输出先手必胜时第一次操作的火柴数目及位置后操作后的火柴数目

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 500000 + 10;
int a[maxn];

int main()
{
    int n;
    scanf("%d", &n);
    int ans = 0;
    for (register int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
        ans = ans ^ a[i];
    }
    if(ans == 0) printf("lose\n");
    else {
        for(register int i = 0; i < n; i++) {
            if((ans ^ a[i]) < a[i]) {
                printf("%d %d\n", a[i] - (ans ^ a[i]), i + 1);
                for(register int j = 0; j < n; j++) {
                    if(j == i) printf("%d ", ans ^ a[j]);
                    else printf("%d ", a[j]);
                }
                break;
            }
        }
    }
}

第一步即将必赢态转移到必输态即异或和为0的状态,即求取出异或和为0的数目及状态。
a1^a2^a3…^an = x
a1^a2^a3…^an^x = 0
a1^a2…^(ak^x)…^an = 0
将ak^x视为新的火柴堆,要满足移动火柴条件,则ak^x < ak,移动火柴数目即为ak - ak^x

猜你喜欢

转载自blog.csdn.net/weixin_40588429/article/details/83867968