POJ1704
emmmm于是我咕咕咕了图论相关总结和数论相关总结。
现在暂时欠着吧....NOIP前一定补上,不会咕不会咕
于是先来水一道博弈,然而我看完题解才会.....
POJ1704
格鲁吉亚和鲍勃决定玩自己发明的游戏。他们在纸上绘制一排网格,将网格从左到右依次为1,2,3,......,并将N个西洋棋棋子放在不同的网格上,如下图所示:
格鲁吉亚和鲍勃依次移动西洋棋棋子。每次玩家选择一个棋子,并将其移动到左边而不越过任何其他西洋棋棋子或横跨左边缘。玩家可以自由选择棋子移动的步数,其中约束棋子必须至少移动一步,一个网格最多可以包含一个棋子。无法移动的玩家输掉游戏。
基于女士优先的原则,格鲁吉亚总是首发。假设格鲁吉亚和鲍勃都在比赛中尽了最大努力,也就是说,如果他们中的一个知道赢得比赛的方式,他或她将能够执行。
鉴于n个西洋棋棋子的初始位置,你能预测谁将最终赢得比赛吗?
基于女士优先的原则,格鲁吉亚总是首发。假设格鲁吉亚和鲍勃都在比赛中尽了最大努力,也就是说,如果他们中的一个知道赢得比赛的方式,他或她将能够执行。
鉴于n个西洋棋棋子的初始位置,你能预测谁将最终赢得比赛吗?
输入
输入的第一行包含单个整数T(1 <= T <= 20),即测试用例的数量。然后是T案例。每个测试用例包含两行。第一行由一个整数N(1 <= N <= 1000)组成,表示西洋棋棋子的数量。第二行包含N个不同的整数P1,P2 ... Pn(1 <= Pi <= 10000),它们是n个西洋棋棋子的初始位置。
输出
对于每个测试案例,如果格鲁吉亚将赢得比赛,打印一行“Georgia will win”; 如果鲍勃将赢得比赛,“Bob will win” 否则'Not sure'。
先将棋子按照位置升序排序,从后往前将他们两两绑定,显然若是偶数个棋子,最后刚好绑定结束,但若是奇数个,最后就会多出来一枚棋子
这枚多出来的棋子显然只可能是左边的第一颗棋子,那么我们将这颗棋子和左边缘绑定起来
从左到右观察
我们可以发现,对于第一堆,显然有意义的只有堆之间两枚被绑定的棋子的距离,同样我们能发现,第一枚棋子无论向左移动多少个位置
显然第二枚棋子总能移动相同的格子。也就是说,一对棋子与另一对棋子之间有多少个空位置堆结果是没有影响的,那么我们就只需要考虑同一对棋子之间的距离
我们把每一对棋子之间的空位视作一堆石子,在对手移动每对石子靠右的那一颗时,移动几位就相当于取几个石子,各堆的石子取尽,相当于不能再取石子
但是显然存在一些情况,因为题目规则并没有限制,所以如果我将每一对的棋子的左端棋子移动,就会导致堆中石子数增加
然而显然的是,若对手这么做要破坏棋局,我们可以将当前堆的右端棋子移动相同的步数,使堆中的棋子恢复到原来的数量,这样棋局就变的相当于没有改变
所以这种状况我们可以直接无视。
这样我们就转化成了简单的NIM问题
于是我们能够发现,根本不存在Not sure。因为NIM博弈,不存在平局!
1 #include<iostream> 2 #include<iomanip> 3 #include<cstdio> 4 #include<ctime> 5 #include<cmath> 6 #include<cstring> 7 #include<algorithm> 8 #include<cstdlib> 9 #include<stack> 10 #include<queue> 11 #include<map> 12 #include<vector> 13 using namespace std; 14 const int maxn = 2100; 15 int T; 16 int n, p[maxn]; 17 int shiki[maxn], top = 0; 18 19 inline int read() { 20 int x = 0, y = 1; 21 char ch = getchar(); 22 while(!isdigit(ch)) { 23 if(ch == '-') y = -1; 24 ch = getchar(); 25 } 26 while(isdigit(ch)) { 27 x = (x << 1) + (x << 3) + ch - '0'; 28 ch = getchar(); 29 } 30 return x * y; 31 } 32 33 int main() { 34 T = read(); 35 while(T--) { 36 memset(p, 0, sizeof(p)); 37 memset(shiki, 0, sizeof(shiki)); 38 n = read(); top = 0; 39 for(int i = 1; i <= n; ++i) p[i] = read(); 40 sort(p + 1, p + n + 1); 41 for(int i = n; i >= 1; i -= 2) { 42 if(i == 1) { 43 shiki[++top] = p[i] - 1; 44 break; 45 } 46 shiki[++top] = p[i] - p[i - 1] - 1; 47 } 48 int ans = 0; 49 for(int i = 1; i <= top; ++i) 50 ans ^= shiki[i]; 51 if(ans) printf("Georgia will win\n"); 52 else printf("Bob will win\n"); 53 } 54 return 0; 55 }