HDU5088——Revenge of Nim II(高斯消元&矩阵的秩)(BestCoder Round #16)

Revenge of Nim II

Problem Description
Nim is a mathematical game of strategy in which two players take turns removing objects from distinct heaps. On each turn, a player must remove at least one object, and may remove any number of objects provided they all come from the same heap.
---Wikipedia
Today, Nim takes revenge on you, again. As you know, the rule of Nim game is rather unfair, only the nim-sum (⊕) of the sizes of the heaps is zero will the first player lose. To ensure the fairness of the game, the second player has a chance to move some (can be zero) heaps before the game starts, but he has to move one heap entirely, i.e. not partially. Of course, he can’t move all heaps out, at least one heap should be left for playing. Will the second player have the chance to win this time?
Input
The first line contains a single integer T, indicating the number of test cases.
Each test case begins with an integer N, indicating the number of heaps. Then N integer Ai follows, indicating the number of each heap.
[Technical Specification]
1. 1 <= T <= 100
2. 1 <= N <= 1 000
3. 1 <= Ai <= 1 000 000 000 000
Output
For each test case, output “Yes” if the second player can win by moving some (can be zero) heaps out, otherwise “No”.
Sample Input
3
1
2
3
2 2 2
5
1 2 3 4 5
Sample Output
No
Yes
Yes

题目大意:

    Nim的复仇。有N堆石子,后手可以在游戏开始前拿走任意堆石子再进行Nim博弈,问后手是否有机会赢。

解题目标:

    先来复习一下Nim博弈。

    给定N堆石子,假设第i堆石子有a[i]个石头子,两个人轮流从某一堆中取任意多的物品,规定每一次至少取一个,多者不限,最后取光者胜。

    Nim博弈的常规解法:k=a[1]^a[2]^a[3]^....^a[n]

      若k==0 先手必输

      若k!=0  后手必输

    显然这个题的目标就是 找出石子堆集合的一个子集(子集元素个数大于等于2),使其元素异或之后为0即可。

解题思路:

    错误思路:

        做比赛的时候,想着用随机化算法来水过去,循环了350W次,提交了3遍。。 发现N<=1000,随机化算法不可能过。。

    正确思路:

        大牛的blog就是不一般。思路就一两句话,研究了整整一天,才勉强看懂。(一大牛题解就三个字:位运算。。Orz)

        根据官方题解的思路来看,要把这些数字看成一个二进制矩阵

        该矩阵具有一下性质:

        (1)每一个空都是1或0

        (2)相对于只有1或0两个值的矩阵元素,那么异或运算相当于其加减法:1+1=0  1+0=1  0+1=1  0+0=0  1-1=0  1-0=1  0-1=1  0-0=0

        再根据矩阵的秩与极大无关组的相关定理可知:若矩阵的秩rank<N,那么极大无关组的成员数要小于N,那么对于任意一个a[i](特别对于不属于极大无关组的a[i])都可以用极大无关组中的成员来进行表示。

        在根据性质:对于任意数a,a^a=0可知,当且仅当rank<N时,存在一个子集使其异或值为0。

解题方法:

    据说是高斯消元。将矩阵化成梯形,那么存在空行,即rank<N。

    ps:前面说了,异或在二进制中相当于加减。与矩阵的初等变化不矛盾。

Code:

 1 /*************************************************************************
 2     > File Name: BestCode#16_1003.cpp
 3     > Author: Enumz
 4     > Mail: [email protected]
 5     > Created Time: 2014年11月01日 星期六 17时44分16秒
 6  ************************************************************************/
 7
 8 #include<iostream>
 9 #include<cstdio>
10 #include<cstdlib>
11 #include<string>
12 #include<cstring>
13 #include<list>
14 #include<queue>
15 #include<stack>
16 #include<map>
17 #include<set>
18 #include<algorithm>
19 #include<cmath>
20 #include<bitset>
21 #include<time.h>
22 #include<climits>
23 #define MAXN 3000
24 using namespace std;
25 long long a[MAXN];
26 int main()
27 {
28     int T;
29     cin>>T;
30     while (T--)
31     {
32         int N;
33         cin>>N;
34         for (int i=1;i<=N;i++)
35             scanf("%I64d",&a[i]);
36         int row=1,col=1;
37         for ( ;row<=N&&col<=40;col++,row++)  //有数据范围可知,化成二进制之后,列数不会超过40
38         {
39             int tmp_row;
40             for (tmp_row=row;tmp_row<=N;tmp_row++) //找到当前列下的第一个不为零的值
41                 if (a[tmp_row]&(1LL<<col))  //判断是否为1
42                     break;
43             if (tmp_row==N+1)               //不存在为1的点,说明存在一个空行,rank--
44             {
45                 row--;
46                 continue;
47             }
48             swap(a[tmp_row],a[row]);    //交换行
49             for (int i=tmp_row+1;i<=N;i++)
50                 if (a[i]&(1LL<<col))
51                     a[i]^=a[row];
52         }
53         if (row<N)
54             printf("Yes\n");
55         else
56             printf("No\n");
57     }
58     return 0;
59 }

    

时间: 2024-12-06 19:00:12

HDU5088——Revenge of Nim II(高斯消元&矩阵的秩)(BestCoder Round #16)的相关文章

hdu 5088 Revenge of Nim II(高斯消元)

题目链接:hdu 5088 Revenge of Nim II 题目大意:Nim游戏的变形,因为游戏很不公平,所以现在转变规则,后手可以选取若干堆石子剔除,剩下堆的石子用 来进行游戏,问说后手可能胜利吗. 解题思路:其实即为取出非0堆石子,使得Nim和为0.因为是Nim和(亦或),所以以每个位建立方程,列出40个方 程,进行亦或形式的高斯消元,因为全0肯定为一解,所以方程肯定有解,那么存在多解的情况即为存在自有变元. #include <cstdio> #include <cstring

HDU5088Revenge of Nim II(高斯消元求自由变元个数)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5088 题意: 有n堆石头,可以去掉其中的一些堆(保证至少剩下一堆)问存不存在一种方法使第二个人赢: 分析: 这k个数边构成了一个01矩阵.那么能异或出0的充分条件是对这01矩阵高斯消元以后矩阵的秩小于矩阵的行数(也即存在一行全零,全零行就是异或出来的一行),那么我们只要对这个01矩阵高斯消元即可. 代码如下: #include<cstdio> #include<cstring> #in

BZOJ 3105: [cqoi2013]新Nim游戏 [高斯消元XOR 线性基]

以后我也要用传送门! 题意:一些数,选择一个权值最大的异或和不为0的集合 终于有点明白线性基是什么了...等会再整理 求一个权值最大的线性无关子集 线性无关子集满足拟阵的性质,贪心选择权值最大的,用高斯消元判断是否和已选择的线性相关 每一位记录pivot[i]为i用到的行 枚举要加入的数字的每一个二进制为1的位,如果有pivot[i]那么就异或一下(消元),否则pivot[i]=这个数并退出 如果最后异或成0了就说明线性相关... #include <iostream> #include &l

BZOJ 3569 DZY Loves Chinese II 高斯消元

题目大意:给定一个[魞歄连通图],多次询问当图中某k条边消失时这个图是否联通 强制在线 我们找到这个图的任意一棵生成树 然后对于每条非树边将其的权值赋为一个随机数 对于每条树边 我们将这条树边的权值设为所有覆盖这条树边的边权的异或和 那么图不连通当且仅当删除一条树边和覆盖这条树边的所有边集 而由于刚才的处理一条树边和覆盖这条边的所有边集的异或和为零 于是问题转化成了对于给定的k条边是否存在一个边权的异或和为零的子集 果断高斯消元 由于使用了随机化所以碰撞率极低 好方法学习了...构思真是巧妙 记

HDU5088(高斯消元)

Revenge of Nim II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 443    Accepted Submission(s): 157 Problem Description Nim is a mathematical game of strategy in which two players take turns r

ACM学习历程—HDU 3915 Game(Nim博弈 &amp;&amp; xor高斯消元)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3915 题目大意是给了n个堆,然后去掉一些堆,使得先手变成必败局势. 首先这是个Nim博弈,必败局势是所有xor和为0. 那么自然变成了n个数里面取出一些数,使得xor和为0,求取法数. 首先由xor高斯消元得到一组向量基,但是这些向量基是无法表示0的. 所以要表示0,必须有若干0来表示,所以n-row就是消元结束后0的个数,那么2^(n-row)就是能组成0的种数. 对n==row特判一下. 代码:

BZOJ 3563 DZY Loves Chinese / BZOJ 3569 DZY Loves Chinese II 随机化+高斯消元解异或方程组

题目大意:给出一个无向图,问删掉k条边的时候,图是否联通. 思路:虽然我把这两个题放在了一起,但是其实这两个题可以用完全不同的两个解法来解决. 第一个题其实是DZY出错了...把每次的边数也异或了,那就直接用这个性质一个一个往后推就行了..最后一个暴力求一下.. 第二个题才是本意啊. 听到做法的时候我惊呆了.. 首先是将整个图中拆出一个树,那么所有边就分为树边和非树边.将所有非树边都加一个随机权值.树边的权值是所有能够覆盖它的非树边的权值的异或和. 把整个图拆开的充要条件是拆掉一条树边,同时将所

BZOJ 3759 Hungergame 博弈论+高斯消元

题目大意:给定一些箱子,每个箱子里有一些石子,两个人轮流操作,每个人可以进行以下操作之一: 1.打开任意多的箱子 2.从一个打开的箱子中拿走任意多的石子 不能操作者判负,求先手是否必胜 先手必胜的状态为:给出的数字集合存在一个异或和为零的非空子集,则先手必胜 证明: 首先我们有状态A:当前的所有打开的箱子中的石子数异或和为零,且所有关闭的箱子中的石子数的集合中不存在一个异或和为零的非空子集 易证A状态时先手必败 先手有两种操作: 1.从一个打开的箱子中拿走一些石子 那么根据Nim的结论 后手可以

【枚举】【高斯消元】Gym - 101412D - Find the Outlier

给你一个未知的d次多项式在0,1,...,d+2处的取值,其中有且只有一个是错的,问你哪个是错的. 枚举哪个是错的,再在剩下的d+2个中取d+1个高斯消元,解出多项式系数,然后代一下最后剩下的那个数看看是否合法,如果合法再看看那个错的是否真的错了. #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> using namespace std; #define N 11 d