題目
結果填空(滿分29分)
標題:海盜與金幣
12名海盜在一個小島上發現了大量的金幣,後統計一共有將近5萬枚。
登上小島是在夜裏,天氣又不好。由於各種原因,有的海盜偷拿了很多,有的拿了很少。
後來爲了“均貧富”,頭目提出一個很奇怪的方案:
每名海盜都把自己拿到的金幣放在桌上。然後開始一個遊戲。
金幣最多的海盜要拿出自己的金幣來補償其他人。
補償的額度爲正好使被補償人的金幣數目翻番(即變爲原來的2倍)。
遊戲要一直進行下去,直到無法完成。
(當金幣數最多的不只一個人或最多金幣的人持有金幣數不夠補償他人的)
遊戲就這樣緊張地進行了,一直進行了12輪,恰好每人都“放血”一次,
更離奇的是,剛好在第12輪後,每個人的金幣數居然都相等了!! 這難道是天意嗎?
請你計算,遊戲開始前,所有海盜的初始金幣數目,從小到大排列,中間有一個空格分開。
答案形如:
8 15 29 58 110 …
當然,這個不是正確答案。
注意:需要提交的是一行空格分開的整數,不要提交任何多餘的內容。
分隔符要用一個西文的空格,不要用其它符號(比如逗號,中文符號等)
題解
答案爲:13 25 49 97 193 385 769 1537 3073 6145 12289 24577
先算出所有人平均的金幣數是多少。得知所有人平均金幣數後,再暴力求出最開始時的金幣數。
求出平均金幣數
首先"剛好在第12輪後,每個人的金幣數居然都相等了"可以知道所有人的總金幣數一定是12的倍數。設第十二輪後每個人都相等的金幣數爲d。(12*d < 總金幣數50000,d > 0,且是一個整數)
在第十一輪時,最後補償金幣的人(下文簡稱L)已經被其他所有人(下文簡稱O)補償了11次(L的原金額已經翻了11倍),他只要最後補償O(補償的額度爲正好使被補償人的金幣數目翻番),那麼所有人金幣數都相等了。
由此可知L在第十一輪補償結束時,他金幣數爲:d + 11 * d / 2。並且L總共被補償了11次,也就是說L原來的金幣數翻倍了11次。
設L原本持有金幣數爲x(x最小爲1),則在第十一輪後他金幣數翻了11倍爲:x*(1<<11),也就是x*(2^11),2048*x。
由此可以得出公式,第十一輪時L的持有金幣數爲:d+11 * d / 2 = 2048 * x。化簡:13*d/4096=x。
由於我們不知道L在十一輪時持有的金幣數x時多少,但是我們要保證d範圍爲:12 * d < 50000(也就是d < 4167,並且d 要接近 4167)。
在 d < 4167這個範圍裏,我們可以求出x的最大值爲:x = 13。
通過L原本持有的金幣數x,帶入13 * d / 4096=13中,我們可以知道d的值爲:4096。
得知第十二輪所有人都相等的金幣數d後,可以暴力求取出最開始時的金幣數。
參考:https://blog.csdn.net/janhezz/article/details/95047424
import java.util.Arrays;
/**
* @author ChangSheng
* @date 2020-04-05
*/
public class P1_海盜與金幣 {
public static void main(String[] args) {
int[] gold = new int[12];
// 第12輪所有人都相等的金幣數d
Arrays.fill(gold, 4096);
// 12個海盜
for (int i = 0; i < 12; i++) {
int sum = 0;
// 其他海盜補償給當前海盜
for (int j = 0; j < 12; j++) {
if (i == j) continue;
gold[j] /= 2;
sum += gold[j];
}
gold[i] += sum;
}
String ans = Arrays.toString(gold).replaceAll(",", " ");
System.out.println(ans.substring(1, ans.length()-1));
}
}