【BZOJ 3150】新Nim游戏

时间:2024-06-26 21:06:50

http://www.lydsy.com/JudgeOnline/problem.php?id=3105

并不会QwQ

为什么贪心是正确的。

向小神请教了一个弱智问题(小神好神啊OTZ)

然后就写了一下好写好调的线性基糊弄糊弄。。。

2016-12-21UPD:补一下拟阵的证明:

设拟阵\(M=(S,L)\),S为所有石子数的集合,L为石子数的子集的所有子集异或和非0的集合。

遗传性:显然。。。

交换性:设\(A∈L\),\(B∈L\),且\(|A|<|B|\)。我们需要证明存在\(x∈B-A\),使得\(A∪\{x\}∈L\)。反证法:假设所有\(\{x\}\),A集合加上\(\{x\}\)后存在子集异或和为0,那么A的线性基包含B的线性基。又因为\(|A|<|B|\),所以B的子集数目大于A的子集数目。由鸽巢原理得:一定存在B的两个子集,两个子集各自的异或和都等于A中一个子集的异或和,那么这两个子集的异或和相等,与\(B∈L\)不符,所以得证。

然后直接贪心啦

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int in() {
int k = 0; char c = getchar();
for(; c < '0' || c > '9'; c = getchar());
for(; c >= '0' && c <= '9'; c = getchar())
k = k * 10 + c - 48;
return k;
} bool flag;
long long ans = 0, sum = 0;
int n, a[103], lb[33], p; int main() {
n = in();
for(int i = 1; i <= n; ++i)
a[i] = in(), sum += a[i];
stable_sort(a + 1, a + n + 1); for(int i = n; i >= 1; --i) {
flag = false;
p = a[i];
for(int j = 30; j >= 0; --j)
if (a[i] >> j & 1)
if (!lb[j]) {
lb[j] = a[i];
flag = true;
break;
} else
a[i] ^= lb[j];
if (!flag) ans += p;
}
printf("%lld\n", ans == sum ? -1 : ans);
return 0;
}