FJOI2015 金幣換位問題

2022-04-29 09:06:10 字數 3699 閱讀 5092

桌子上有2n+2個位置,其中前n個位置放著n個正面朝上的硬幣,接下來n個位置放著反面朝上的硬幣,後面兩個位置為空。

每次操作可以將任意兩個相鄰的硬幣順序不變地移動到空位上,那麼至少要多少次操作可以將硬幣移成正反相間(正面的硬幣在第乙個,最後兩個還是空)。

例如:當n = 4時,有一組合法解如下:

11110000__

__11000011

101__00011

1010100__1

10101__001

10101010__

輸入乙個n

第一行輸出最少移動步數

接下來一行為移動方案,只要輸出被移動的兩個非空格格仔左邊那個的編號。換不換行無所謂。詳見樣例。

4
5

1 4 8 6 9

對於100%的資料,2分析:

首先需要先找到最少步數與n的關係,在考場上找到的是當

n為偶數時,最少步數f(

n) = n * 2 - 3,當n

為奇數時,f(

n) = n * 2 - 2

,然後發現構造過程也很容易,隨便搞搞就可以了。

後來成績出來,發現這一題沒分。而且,全場都沒有人有拿到分。。。很多人想到是n + 1

,但是沒有人構造出過程。

回來之後,寫了個暴力,只跑到n = 8

的情況(再大記憶體受不了),發現答案確實是

n + 1

。乙個學長說這很像acm world final 2014

的第一題,就去研究了一下,但是按那道題的方法最終的結果是

0101……

也沒有想到怎麼將它轉換為

1010……

後來cjk

花了一整天的時間研究出一些思路,大致是分解成子問題,每次規模減小,後來又一步步完善,之後變成這樣:

對於乙個類似11111111000000__00

的子問題,可以轉換為

10101010__10101010(__

可以在任意0和

1之間,但是不能是

1__0

),步驟如下:

11111111000000__00

1__111110000001100

1001(111100__00)1100 (括號內表示下乙個子問題)

子問題解決之後,再經過下面的轉換:

1001(1010__1010)1100

1001(1010101010)1__0

10__(1010101010)1010

這樣就將當前的子問題解決了且子問題規模每次縮小4

,而每次增加的步數也是

4,那麼就可以符合我們的要求。

由於n > 2,所以

我們的問題要從

3開始處理(而且1本身就是結果,2無法解決),3、

4、5、

6無法再分解為子問題,所以要內建3、

4、5、

6的解法和對應子問題的解法。

然後我又在暴力的基礎上加了輸出所有解,找出了3、4

、5、6

的可行方案,分別是:

3:2 6 4 7

4:1 4 8 6 9

5:2 7 11 3 8 11

6:1 6 12 9 3 10 13

然後子問題的解決方案:

3:6 2 5

4:8 1 4 7

5:8 3 11 2 7

6:10 2 12 9 6 3

以3來舉個例子,當規模為

3的子問題出現的時候,應該是這樣:

1__1(11100000)1100

然後第一步將第6、7

個位置上的

0移開,變成

1001(11100__0)1100

接下來依次操作:

1001(1__00110)1100

1001(1010__10)1100

然後就可以解決外面的子問題了。

現在需要確定操作的規律,我們定義當前子問題的規模為n

,起點為

l,上一步操作為

m,任意舉乙個例子

n = 11

的情況:

1111111111100000000000__

11111111111000000000__00        n = 11   l = 0   m = 21 = l + n * 2 - 1

1__111111110000000001100        n = 11   l = 0   m = 2 = l + 2

1001(111111100000__00)1100        n = 7   l = 4   m = 17 = l + n * 2 - 1

1001(1__1111000001100)1100        n = 7   l = 4   m = 6 = l + 2

1001(1001(11100__0)1100)1100        n = 3   l = 8   m = 14 = l + 6

1001(1001(1__00110)1100)1100        n = 3   l = 8   m = 10 = l + 2

1001(1001(1010__10)1100)1100        n = 3   l = 8   m = 13 = l + 5

1001(1001101010101__0)1100        n = 7   l = 4   m = 18 = l + n * 2

1001(10__101010101010)1100        n = 7   l = 4   m = 7 = l + 3

100110101010101010101__0        n = 11   l = 0   m = 22 = l + n * 2

10__10101010101010101010        n = 11   l = 0   m = 3 = l + 3

1010101010101010101010__        n = 11   l = 0   m = 23 = l + n * 2 + 1

從上面的過程中,我們可以發現一些規律,每次縮小規模時,解決子問題之前的操作都是l + n * 2 - 1 

和 l + 2

,而解決子問題之後的操作都是

l + n * 2

和l + 3

,中間規模為3~

6的子問題特殊解決,然後大問題的最後一部都是將末尾兩個移到前面,因為解決規模為3~

6的子問題需要的步驟分別是3~

6,加上最後一步,需要的運算元剛好是

n + 1

。**:

1 #include 2

intn, l;

3int

main ()416

return0;

17}18for (l = 0; n >= 7; n -= 4, l += 4

)19 printf ("

%d %d

", l + (n << 1) - 1, l + 2

);20

switch

(n)21

27for (l -= 4, n += 4; l >= 0; l -= 4, n += 4

)28 printf ("

%d %d

", l + (n << 1), l + 3

);29 n -= 4

;30 printf ("

%d ", (n << 1) + 1

);31 }

FJOI2015 火星商店問題

線段樹分治。以時間軸建立線段樹,每乙個線段樹節點,存放 l,r 時間內,有影響的操作1,建立可持久化trie樹,trie樹以商店位置為root,就可以支援商店的區間查詢,然後將操作0,按照商店位置排序,進行線段樹分治,每次到乙個節點,先把操作0插入trie樹,然後把所有當前時間記憶體的有影響的操作1...

題解 FJOI2015火星商店問題

好幾天之前做的題目了,一直想寫一下部落格也沒騰出時間來,今天趕緊把坑給填上呼呼呼 這道題首先如果只考慮每個商店中沒有時間限制的物品時,我們只需要使用一棵可持久化trie樹來維護區間內的異或最大值即可,這樣我們可以把兩部分的問題分離開來。之後我們再考慮有時間限制與編號限制的情況下,該怎樣做?無腦做法線...

洛谷 FJOI2015 火星商店問題

初見安 這裡是傳送門 洛谷p4585 fjoi2015 火星商店問題 聽說是分治線段樹套可持久化trie 蒟蒻不會分治線段樹,就寫了乙個線段樹套trie。題意就是 n個初始為空的集合,m個操作。操作有 向某集合中加入乙個整數或查詢最近d次向編號在 l,r 中的集合加入的元素中,與x異或的最大值。我們...