Return of the Nim
Problem Description
Sherlock and Watson are playing the following modified version of Nim game:
- There are n piles of stones denoted as
,
,...,
, and n is a prime number;
- Sherlock always plays first, and Watson and he move in alternating turns. During each turn, the current player must perform either of the following two kinds of moves:
- Choose one pile and remove k(k >0) stones from it;
- Remove k stones from all piles, where 1≤k≤the size of the smallest pile. This move becomes unavailable if any pile is empty.
- Each player moves optimally, meaning they will not make a move that causes them to lose if there are still any better or winning moves.
Giving the initial situation of each game, you are required to figure out who will be the winner
Input
The first contains an integer, g, denoting the number of games. The 2×g subsequent lines describe each game over two lines:
1. The first line contains a prime integer, n, denoting the number of piles.
2. The second line contains n space-separated integers describing the respective values of ,
,...,
.
- 1≤g≤15
- 2≤n≤30, where n is a prime.
- 1≤pilesi≤
where 0≤i≤n−1
Output
For each game, print the name of the winner on a new line (i.e., either "Sherlock
" or "Watson
")
Example Input
2 3 2 3 2 2 2 1
Example Output
Sherlock Watson
省赛时候的博弈,被划分到了难的系列,所以没怎么敢攻这题,再加上入了某题的深坑...
这题本质上是一个威佐夫和Nim的结合,但网上有大佬说是Matrix Nim,真心没听过啊...网上也没找到相关的知识点...
其实感觉省赛时候要是分析分析应该能猜出来的...
当n = 2时,很明显的一个威佐夫博弈。
当n > 2时,可以发现去掉从所有堆中取k个操作就是一个Nim。
而进行这个取k个操作会产生什么影响呢,举个例子,(偷挪网上大佬的例子..)
有3堆石子,分别是15,6,9 然后转换为二进制形式
1 1 1 1
0 1 1 0
1 0 0 1
此时为P态,进行普通Nim操作肯定会破会P态转移到N态,所以此时不会选取这种操作,那么只能尝试对每堆进行取任意满足条件的k个石子,发现不管怎么取完之后P态也必定会被破坏。原因是,假如对每堆取K个它们二进制最小的位代表的个数个,则取完之后此位的二进制值都会被取反,所以破坏了P态,而且题目的要求是素数个堆(除2外都是奇数),对其他满足条件的二进制位进行取也是如此。所以当>2堆时,对P态进行取同k个操作只会破坏P态,而不会得到想要的P态——>P态,而当为N态时,只需进行普通的Nim操作就可使N态转化为P态,故加入同取k个操作之后也是满足普通Nim堆的。
所以难点在于分析同取k操作的影响,不过大佬说是1*n的Matrix Nim,所以盼望有资料的哥哥姐姐能给小弟贴一份..
代码:
#include <iostream>
#include <string.h>
#include <cstdio>
#include <cmath>
using namespace std;
double gold = (sqrt(5.0)+1.0)/2.0;
int main(){
int g, n, a, b;
scanf("%d", &g);
while(g--){
scanf("%d", &n);
if(n == 2){
scanf("%d %d", &a, &b);
if(a > b) swap(a, b);
int key = (b-a)*1.0*gold;
if(key == a) printf("Watson\n");
else printf("Sherlock\n");
continue;
}
int x, ans = 0;
for(int i = 1; i <= n; ++i){
scanf("%d", &x);
ans ^= x;
}
if(ans) printf("Sherlock\n");
else printf("Watson\n");
}
return 0;
}
/***************************************************
User name: 薄层
Result: Accepted
Take time: 0ms
Take Memory: 204KB
Submit time: 2017-05-08 20:50:01
****************************************************/
继续加油~