HAOI2015 陣列遊戲

2022-05-20 19:07:11 字數 1538 閱讀 5041

題目大意:

有一排n個格仔,每個格仔上都有乙個白子或黑子,在上面進行遊戲,規則如下:

選擇乙個含白子的格仔x,並選擇乙個數k,翻轉x,2x,...,kx格仔上的子。

不能操作者負。

思路:將「某個格仔上有乙個白子 」視作遊戲的乙個狀態。

對於狀態x,sg(x)=mex。

由於sg函式的取值只與棋盤大小和棋子位置有關,因此我們可以記憶化。

然後我們就有了暴力構造sg函式的程式,實測只能過40%的點,大力卡常以後勉強能50%。

而且空間顯然也開不下,只能用hash_map。

然而這題的sg函式有一些神奇的性質,例如,對於大小為10的棋盤,當x分別為1~10時,sg(x)分別為:

4 1 2 2 2 1 1 1 1 1

我們將它們進行分組:

(4)(1)(2)(2 2)(1 1 1 1 1)

可以發現,當不同棋子可以往後跳的步數相同時,它們的sg函式相同。

顯然可以把它們分為2sqrt(n)組。

其中前sqrt(n)組都是乙個子一組,後sqrt(n)組都是很多個一組。

這樣,以sqrt(n)為界,對於我們需要的函式,判斷一下引數的範圍即可。

1 #include2 #include3 #include4 inline int

getint()

11const

int n=100000;12

int sg[n][2

],mex[n];

13int

n,block;

14 inline int next(const

int &x,const

int &y)

17void

getsg()

25int tmp=1;26

while(mex[tmp]==i) tmp++;

27 ((i>block)?sg[n/i][1]:sg[i][0])=tmp;28}

29}30int

main()

40 puts(ans?"

yes":"no"

);41}42

return0;

43 }

暴力構造sg函式的程式: 

1 #include2 #include3 #include4 #include5 #include6 inline int

getint()

13 __gnu_cxx::hash_mapsg,mex;

14int

n;15

int getsg(const

intx)

21for(sg[x]=1;mex[sg[x]]==x;sg[x]++);

22return

sg[x];23}

24int

main()

32 puts(ans?"

yes":"no"

);33}34

return0;

35 }

view code

HAOI2015 樹上染色

有一棵點數為 n 的樹,樹邊有邊權。給你乙個在 0 n 之內的正整數k,你要在這棵樹中選擇 k 個點,將其染成黑色,並將其他的 n k個點染成白色。將所有點染色後,你會獲得黑點兩兩之間的距離加上白點兩兩之間距離的和的收益。問收益最大值是多少。輸入第一行兩個整數 n,k。接下來 n 1 行每行三個正整...

HAOI2015 樹上染色

考慮子樹當中所有邊的貢獻即可。然後就能簡單做樹上揹包了。但是要注意列舉的順序,應該從大到小更新,否則某個狀態會多次被加。如果不想考慮列舉順序,那麼直接dp的時候用乙個臨時陣列記錄。ac pragma gcc optimize ofast funroll all loops include defin...

HAOI2015 樹上染色

嘟嘟嘟 首先這一眼看出來,要樹形dp。然後發現狀態不好設,剛開始我想的是dp i j 表示以 i 為根的子樹,選了 j 個黑點的最大價值。結果就不會轉移了。轉移的時候想考慮 這一條邊的貢獻,但是發現這個狀態的轉移所涉及的不只是這一條邊,還有子樹中的邊,於是就徹底gg了。還是看了題解。題解也是考慮貢獻...