桌子上有2n+2個位置,其中前n個位置放著n個正面朝上的硬幣,接下來n個位置放著反面朝上的硬幣,後面兩個位置為空。
每次操作可以將任意兩個相鄰的硬幣順序不變地移動到空位上,那麼至少要多少次操作可以將硬幣移成正反相間(正面的硬幣在第乙個,最後兩個還是空)。
例如:當n = 4時,有一組合法解如下:
11110000__
__11000011
101__00011
1010100__1
10101__001
10101010__
輸入乙個n
第一行輸出最少移動步數
接下來一行為移動方案,只要輸出被移動的兩個非空格格仔左邊那個的編號。換不換行無所謂。詳見樣例。
4
5對於100%的資料,2分析:1 4 8 6 9
首先需要先找到最少步數與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 2intn, 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異或的最大值。我們...