【題目描述】
從過去回來後,你又對未來產生了濃厚興趣。你去辦理時空簽證,卻被告知能到未來
的人都必須是高智商的,所以需要玩乙個遊戲來測試智商。
遊戲規則如下:
1. 有一堆石子數為 n 的石子堆,兩個人輪流取,最後不能取的人輸
2. 你是先手,且你不能在第一步將石子全部取完
3. 設上乙個人選的石子數為 x,則這次取的石子數不能超過 x*k
你需要知道你是否能勝利,以及如何勝利
【輸入格式】
第一行乙個正整數 t,表示測試組數
下面的 t 行,每行兩個整數,代表 n 和 k
【輸出格式】
對於每組資料,輸出組數,然後如果先手負,則輸出」lose」,否則輸出最小的第一步取的
石子數,注意中間有空格
【樣例】
sample input
5 16 1
11 1
32 2
34 2
19 3
sample output
case 1: lose
case 2: 1
case 3: 3
case 4: lose
case 5: 4
【備註】
對於 10%的資料,有 n <= 100, k <= 2
對於 30%的資料,有 n <= 10^8, k <= 3
對於 100%的資料,有 2 <= n <= 10^8, k <= 10^5, t <= 200
這個題是一道非常非常好的題,我能做到它真是太幸運了!
為了搞明白其正確性,我參閱了國家集訓隊**,發現這道題從2023年便開始出現在集訓隊**裡,當時它的時間複雜度是o(
n3) (09年集訓隊**說的),然後在09集訓隊**裡,它的時間複雜度推進到了o(n);現在它的時間複雜度是o(
logk
+1kn
) ,可以發現對於這個題這是乙個被卡常數的時間複雜度。。但是由於資料水。。
而作為一道神題的題解,網上的題解(估計都是抄的)都tm是乙個模子,完全講不明白。
我在這裡給出乙個較為嚴謹的思路和證明(這可是我花了一天時間才搞明白的)。
首先呢,化繁為簡,考慮k=1的情況:沒有思路?打表!
打出不同的n,給出的最終答案是多少。
發現當n=2i
時必敗。
然後呢,讓我們考慮一下這是為什麼。
這顯然是與二進位制有關的,於是我們轉二進位制考慮:
減乙個數我們把它視為減去若干個2i
. 那麼我們從高到低減去這些1,如果乙個1對應的被減數字是1,那麼就直接減掉好了;而如果乙個1對應的被減數字是0,那麼就相當於是把上乙個1的位置變成0,而從那裡開始到這一位都變成1.
也就是說,從0減不會讓1減小,而取完所有石子的充要條件是石子數的二進位制中的1的總數是0.
那麼一件有趣的事情就出現了,既然是博弈,那麼應該在每次a取完後,b不管如何取,都只能從0位上減;這顯然是容易做到的,只要a每次取lowbit即可,而b所減的最低位一定會出現乙個1,所以a一定能取到lowbit。而之所以2i
不行,就是因為a第一次取不到lowbit,導致情況反轉了。
而打表發現,確實是lowbit,也就證實了我們的結論。
考慮我們是如果搞出k=1的情況的,
1、打表。(不要小看打表,這是乙個非常非常重要的技巧!)
2、證明出四件事:
①依照某種取法,a每次都能取乙個值;而這麼做將剩給b乙個他不能取到的數,或a把石子全部取走了。
②這個值只要石子數為正,都一定存在。
③這種取法是唯一的。(這雖然是乙個看上去沒有關係的問題,但是在之後的證明中你會發現這才是這個題真正的重點)
④a每次一定能取到這個值。
然後我們開始考慮k=2的情況。
打表發現,必敗態是fibonacci。
下面我們將說明這個問題。
(在以下的敘述中,我們將認為斐波那契數列以1為首項,2為次項)
先介紹——齊肯多夫引理。
任意乙個正整數必然能被表示成斐波那契數列中的若干不連續項(包括一項)之和;
這個定理看起來似乎非常玄妙,但實際上它不過是兩個簡單事實的疊加而已;雖然有的時候形式上的證明是必不可少的,但是我卻認為非形式的證明才能揭示定理的靈魂所在,大段的符號和邏輯轉移往往最關鍵的突破被掩蓋。
顯然1,2(斐波那契數列中的前兩項)可以被用斐波那契數列中的項表示,那麼我們不妨設1..i-1,均能用斐波那契數列中的若干項表示; 設f
j 為最大的小於等於i的斐波那契項,即fj
≤i+1 若
fj=i
,則i可以被斐波那契數列中的項表示; 若f
j<
i ,則fj
−i可以用斐波那契數列中的項表示,而且表示法中最大項−1
;因為若非如此,則有fj
−1+f
j=fj
+1≤i
,這便與前設矛盾了。
綜上,原命題成立。
齊肯多夫定理說明了①②,而實際上③④正是齊肯多夫定理的推論。
若干不相鄰項實際上就是說任意兩項之比大於2,因為fi
=fi−
1+fi
−2而fi−
1>fi
−2(首項是1,次項是2),所以fi
>2∗
fi−2
,即斐波那契數列中若干不連續項之比是大於2的。
也就是說我們可以把乙個不在斐波那契數列上的整數寫成斐波那契二進位制=齊肯多夫拆分的形式,那麼發生的事情就像k=1一樣了;我們只需要取出其所有齊肯多夫拆分中的最小最小項即可。而下面我們將說明實際上,任意整數的齊肯多夫拆分都是唯一的。
③對於i,我們試圖將其用斐波那契數列中的數分解,並依據不能選連續項的原則,那麼顯然,若i只能用fj
分解,則依據上述數學歸納法/dp的方法,易證齊肯多夫分解唯一性。
若i不選fj
,則剩下的fibonacci數能搞出的最大的和顯然是從fj
−1開始往前跳著一直選到乙個1(它不分奇偶都會達到乙個1的),但是這個最大和是多少呢?顯然,這雖然有一坨項,但只需要為它加上乙個1,它就會啪啪啪地全合成一項——fj
,也就是,如果不選fj
的話,我們最大只能搞出fj
−1,亦即,fj
是我們的唯一選擇,即
齊肯多夫分解唯一。
④(這個命題對於斐波那契數列來說有多種證明方式,但是這裡我們介紹一種易於向高維推廣的)
我們考慮a與b博弈,a必勝的時候,在某一輪中,b面對y,y的齊肯多夫拆分最小項為fi
,這次b取了x,y−
x 的齊肯多夫拆分最小項為fj
。 而若f
j>2x
,就意味著fj
大於2倍的x的齊肯多夫拆分的最大項,即x的齊肯多夫拆分可與y−
x 的齊肯多夫拆分簡單合併而得到y,也就是說存在y的齊肯多夫拆分其最小項,然而齊肯多夫拆分是唯一的,所以這種情況是不可能的。即fj
≤2x 必然成立,a每次一定能取到最小項。
然後我們開始試圖向高維推廣齊肯多夫定理及其推論。
考慮齊肯多夫定理的證明過程,顯然我們只需要把fi
=fi−
1+fi
−2換成fi
=fi−
1+fk
|k∗f
k−1−1≤k
∗fk ,就讓齊肯多夫定理中表述的條件若干不連續被若干項,其中任意兩者之比大於k取代了;即原先fi
是兩個fi
−1和它的上一項合併而成,而現在它是由fi
−1和最小的不小於fi
−1k 代替了。
而我們很容易就可以發現,上述四點的證明甚至幾乎不用有太大的變化,便可完全套用在新的數列上;而且足夠嚴謹。
最後我們分析一下時間複雜度的問題,這幾乎已經是顯然的了。
顯然從前一項到後一項,至少要乘k+
1k,而我們需要搞出小於等於n的所有項才行。
所以最後的時間複雜度是o(
tlog
k+1k
n)≈2
∗108 ,常數被卡飛了,極限資料的話怎麼調都是1.0?秒。。而且由於**異常簡單,根本就沒有常數優化的空間,導致非常蛋疼。。
不過。。根據出題人懶惰定律,出題人有相當大地可能性會出隨機資料。而如果是隨機資料的話,可以期望去掉乙個2,0.5s差不多是可以的。。
而事實,也確實是這樣。。
還有一種推數列的方法是搞兩個陣列,實際上與這種遞推是可以互相推出的,寫起來還要麻煩一點;這裡就不再贅述了。
code:
#include
int a[1000000];
inline
int in()
int main()
}}
這道題給我的收穫有:
①對於奇怪的dp、博弈論什麼的,打表尋找規律,再試圖證明規律,便很容易向高維推廣了。
②dp在證明中的應用(dp->數學歸納法):證明第一項成立;證明若前n項成立,則下一項也成立。
③複雜的問題往往看起來難以下手,但實際上如果我們先考慮一些簡單的情況,即使是再複雜的問題便也會迎刃而解了。
poj解題報告 1328
不得不說,這題是讓我飽受折磨,畢竟第一次做貪心演算法,而且wa了好多次,幸好有學長的幫助,最終找到了問題所在,是在快排上是問題,double高位不可向int低位轉換,由於一開始強制轉換導致雖然樣例和其他的測試資料過了,但還是wa,現在改完了就對了,附上ac ps 這題通過率是22 真心不簡單 如下 ...
poj解題報告 2586
這題我是用的貪心演算法,其實不用也可以,列舉也能解決,因為情況不多。因為是每連續5個月必有虧損,而一年只有1 5,2 6,3 7,4 8 8 12共8種情況。現在設盈餘為s,虧損為d,可列出以下幾種情況。ssssdssssdss 4ssssddsssddss 3s 2d ssdddssdddss 2...
poj解題報告 2635
這題特別好理解,就是 坑啊。題意就是給乙個數,這個數是兩個大素數的積,再給出乙個數,如果最小的素數比給的數大,列印good,否則列印bad和最小的素數。這題用的方法是高精度求模 同餘模定理。還有素數打表,把10 6內的素數全部預打表,在求模時則列舉到小於l為止。注意打表不能只打到100w,要保證素數...