博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[CQOI2013]新Nim游戏 线性基
阅读量:4652 次
发布时间:2019-06-09

本文共 1309 字,大约阅读时间需要 4 分钟。

题面

题解

首先我们知道nim游戏先手必败当且仅当所有石堆异或和为0,因此我们的目标就是要使对手拿石堆的时候,无论如何都不能使剩下的石堆异或和为0。

对于一个局面,如果我们可以选取一些可以凑出0的石堆留下(因为不能全部拿走,所以这里至少要拿一堆),那么显然就先手必败了。
因此作为先手,我们留给后手的状态必须是一个凑不出0的状态。
考虑如果一个局面可以凑出0,会具有什么样的特征。
对于一个局面,我们求出它的线性基,如果在线性基外还有别的01串,那么根据线性基的定义,线性基内的串一定可以凑出外面的那个串,然后我们再把用线性基凑出的串和原来的串xor一下就得到0了。
因此我们需要使得留下的局面中,所有串都在线性基内。
所以我们先求出给定串的线性基,然后拿走所有线性基外的串就肯定先手必胜了。
同时为了使得拿走的尽量少,也就是留下的尽量多,所以我们按串的大小,从小到大往线性基内塞串即可

#include
using namespace std;#define R register int#define AC 110#define LL long longint n; LL ans;int s[AC], f[AC];inline int read(){ int x = 0;char c = getchar(); while(c > '9' || c < '0') c = getchar(); while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x;}void pre(){ n = read(); for(R i = 1; i <= n; i ++) s[i] = read(); sort(s + 1, s + n + 1);}void work(){ for(R i = n; i; i --)//从高开始贪心 { int x = s[i]; bool done = false; for(R j = 30, maxn = 1 << 30; ~j; j --, maxn >>= 1) { if(!(x & maxn)) continue; if(!f[j]) {f[j] = x, done = true; break;} else x ^= f[j]; } if(!done) ans += s[i];//没被加入线性基就要拿走 } printf("%lld\n", ans);}int main(){// freopen("in.in", "r", stdin); pre(); work();// fclose(stdin); return 0;}

转载于:https://www.cnblogs.com/ww3113306/p/10354328.html

你可能感兴趣的文章
C#基础之------进制转换
查看>>
年底得了个公司奖金,但是我却高兴不起来
查看>>
SQL Server 下取中位数(中位值)的方法
查看>>
Using databases and Structured Query Language (SQL)
查看>>
网络对抗作业一
查看>>
路径规划效果图
查看>>
JAVA-注解规范
查看>>
Jmeter下进行ip伪造
查看>>
如何解决SQL Server 2008 无法连接到(local)
查看>>
java 向上转型 向下转型
查看>>
mysql的数据结构
查看>>
【目标流畅阅读文献】kick off
查看>>
Python学习之路-26 Socket
查看>>
mysqldump不得不说的秘密
查看>>
优化Android Studio/Gradle构建(转)
查看>>
DDD领域模型数据访问权限之用户权限(十)
查看>>
VM 的安装与简介
查看>>
[转]PHP 判断数组是否为空的几种方法
查看>>
使用watch定时执行命令并显示结果
查看>>
转载:javaweb学习总结(三十)——EL函数库
查看>>