P1247 取火柴游戏

思路:要求如果胜利的话第一步要取第几个及取多少。

先有一个定理:(a_1,a_2,...,a_N)为奇异局势当且仅当a_1\oplus a_2\oplus ...\oplus a_N=0

证明:(a_1,a_2,...,a_N)=(0,0,...0)时显然成立。

否则a_1\oplus a_2\oplus ...\oplus a_N=k\neq0,显然k存在一个最高位。则一定存在一个a_i(1<=i<=N),它在k的最高位的值为1。

因此,a_i\oplus k<a_i(因为最高位变为0了)

a_i{}'=a_i\oplus ka_1\oplus a_2 \oplus a_3 \oplus ...... \oplus a_i{}' \oplus ...... \oplus a_n=a_1\oplus a_2 \oplus a_3 \oplus ...... \oplus a_i \oplus ...... \oplus a_n \oplus k = 0

因此把a_i取走几个后变成a_i \oplus ka_1 \oplus a_2 \oplus a_3 \oplus ...... \oplus a_i \oplus ...... \oplus a_n = 0,使后手必输。

部分参考这个链接

#include<bits/stdc++.h>
using namespace std;
#define ll long long;
const int maxn = 1e6 + 19;
int n;
int a[500005];

int main() {
    scanf("%d", &n);
    int check = 0;
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        check ^= a[i];
    }
    if(!check)
        return 0 * printf("lose\n");
    for(int i = 1; i <= n; i++) {
        if((check ^ a[i]) < a[i]) {
            cout << (a[i] - (check ^ a[i])) << " " << i << endl;
            a[i] = check ^ a[i];
            for(int j = 1; j <= n; j++) {
                cout << a[j] << " ";
            }
            break;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Endeavor_G/article/details/89738759