Being a Good Boy in Spring Festival
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3972 Accepted Submission(s): 2345
春節回家 你能做幾天好孩子嗎
寒假裏嘗試做做下面的事情吧
陪媽媽逛一次菜場
悄悄給爸爸買個小禮物
主動地 強烈地 要求洗一次碗
某一天早起 給爸媽用心地做回早餐
如果願意 你還可以和爸媽說
咱們玩個小遊戲吧 ACM課上學的呢~
下面是一個二人小遊戲:桌子上有M堆撲克牌;每堆牌的數量分別爲Ni(i=1…M);兩人輪流進行;每走一步可以任意選擇一堆並取走其中的任意張牌;桌子上的撲克全部取光,則遊戲結束;最後一次取牌的人爲勝者。
現在我們不想研究到底先手爲勝還是爲負,我只想問大家:
——“先手的人如果想贏,第一步有幾種選擇呢?”
/***************************************************
*
* acm: hdu-1850
*
* title: Being a Good Boy in Spring Festival
*
* time: 2014.5.4
*
***************************************************/
//此題考察博弈論,Nim博弈
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
int j;
int k;
int M; //M堆撲克牌
while (~scanf("%d", &M) && M != 0)
{
int N[101] = {0};
int sum = 0; //除當前堆,剩餘堆得異或值
int num = 0; //必勝結果的選擇數
for (i=1; i<=M; i++)
{
scanf("%d", &N[i]); //每一堆撲克牌的數量
}
for (i=1; i<=M; i++)
{
k = i;
sum = 0;
for (j=1; j < k; j++) //當前堆之前的所有堆
{
sum ^= N[j];
}
for (j = i + 1; j <= M; j++)//當前堆之後的所有堆
{
sum ^= N[j];
}
if (N[k] > sum) //如果當前堆值大於 剩餘堆的異或值 則結果勝利
{
num++;
}
}
printf("%d\n", num);
}
return 0;
}
還有種思路,算是上面程序的優化把
/***************************************************
*
* acm: hdu-1850
*
* title: Being a Good Boy in Spring Festival
*
* time: 2014.5.4
*
***************************************************/
/*
理論:a+b=s,有 b=s+a (a表示某分堆,b表示其餘分堆的異或值,s爲總異或值)
即總異或和s 對任意一個數a取異或 可以的得到其他所有數的異或值b。
思路:if (b = s + a < a) 成立
a可以減到b使其異或爲0 則有必勝策略
e.g
s = 5 + 7 + 9 = 0101 + 0111 + 1001 = 1011B = 11D
b = s + a = 11 + 5 = 1011 + 0101 = 1110B = 14D
b = 7 + 9 = 0111 + 1001 = 1110B = 14D
because : a < b
so: 從5取任何數都無法轉爲必敗點
if (s != 0) 遍歷剩餘所以堆, 必存在能轉爲必敗點的某堆
*/
#include<stdio.h>
#define MAXSIZE 100
int main()
{
int M;
int N[MAXSIZE];
while (~scanf("%d", &M) && M != 0)
{
int i;
int sum = 0;
int num = 0;
for (i = 0; i < M; i++)
{
scanf("%d", &N[i]);
sum ^= N[i];
}
for (i = 0; i < M; i++)
{
if (N[i] > (N[i]^sum))
{
num++;
}
}
printf("%d\n", num);
}
return 0;
}