AcWing 894 拆分 Nim遊戲

2021-10-01 22:01:32 字數 1209 閱讀 4206

題目描述:

給定n堆石子,兩位玩家輪流操作,每次操作可以取走其中的一堆石子,然後放入兩堆規模更小的石子(新堆規模可以為0,且兩個新堆的石子總數可以大於取走的那堆石子數),最後無法進行操作的人視為失敗。

問如果兩人都採用最優策略,先手是否必勝。

輸入格式

第一行包含整數n。第二行包含n個整數,其中第i個整數表示第i堆石子的數量ai。

輸出格式

如果先手方必勝,則輸出「yes」。否則,輸出「no」。

資料範圍

1≤n,ai≤100

輸入樣例:

2

2 3

輸出樣例:

yes
分析:

首先回憶下nim遊戲問題,之所以可以直接將各堆石子數目異或起來,是因為各堆石子取多少不受限制,因此,對於石子數目為x的一堆,可以到達比x小的任何狀態,故sg(x) = x,因此石子數目的異或和本質上就是sg函式值的異或和。再回憶下有向圖遊戲的和,多個有向圖遊戲的sg值等於所有有向圖sg函式值的異或和。

對本題而言,可以拿走一堆石子,然後放入兩堆石子,新放入的石子數目可以是0,每堆數目都不能超過拿走的那一堆,但是兩堆的總數目可以超過拿走的那一堆。也就說是,一次操作相當於把乙個有向圖轉化為了兩個有向圖,sg可到達的狀態就是新產生的兩個有向圖狀態的異或和,我們只需要求出各堆石子數目的sg函式值,異或起來得到的異或和非0就可以判斷先手必勝了。也就是說拿取石子規則的改變只是改變了有向圖狀態變化的方向,影響了石子數目的sg值,並不影響有向圖遊戲的定理。

如何求本題的sg函式值呢?

int sg(int x)

}

需要用二重迴圈列舉新產生的兩堆石子可能的數目,第一堆石子的可能數量是0到x-1,為了避免重複列舉,第二堆石子的數目數量設定為0到第一堆石子的數目,遞推式也就是可到達的狀態sg函式值等於新產生兩堆石子sg函式值的異或和。其它步驟與上一題求sg函式的步驟別無二致。

#include #include #include using namespace std;

int g[105];

int sg(int x)

}int main()

if(res) puts("yes");

else puts("no");

return 0;

}

AcWing 日期問題

小明正在整理一批歷史文獻。這些歷史文獻 現了很多日期。小明知道這些日期都在1960年1月1日至2059年12月31日。令小明頭疼的是,這些日期採用的格式非常不統一,有採用年 月 日的,有採用月 日 年的,還有採用日 月 年的。更加麻煩的是,年份也都省略了前兩位,使得文獻上的乙個日期,存在很多可能的日...

AcWing 小貓爬山

翰翰和達達飼養了n只小貓,這天,小貓們要去爬山。經歷了千辛萬苦,小貓們終於爬上了山頂,但是疲倦的它們再也不想徒步走下山了 嗚咕 翰翰和達達只好花錢讓它們坐索道下山。索道上的纜車最大承重量為w,而n只小貓的重量分別是c1 c2 cn。當然,每輛纜車上的小貓的重量之和不能超過w。每租用一輛纜車,翰翰和達...

約數之和(acwing)

假設現在有兩個自然數a和b,s是ab 的所有約數之和。請你求出s mod 9901的值是多少。輸入格式 在一行中輸入用空格隔開的兩個整數a和b。輸出格式 輸出乙個整數,代表s mod 9901的值。資料範圍 0 a,b 5 107 輸入樣例 2 3輸出樣例 注意 a和b不會同時為0。include ...