51Nod1306 高樓和棋子 動態規劃

2022-03-31 15:20:54 字數 1124 閱讀 1452

有個n層的高樓和若干個棋子,所有的棋子都是一樣的。棋子從樓的某層e扔到地上不會碎(0 <= e <= n),但從比這個樓層高的地方扔到地上都會碎。給出樓的高度n,以及棋子的數量m,你來找出這個e(0 <= e <= n),問最壞情況下需要實驗多少次才能計算出準確的e(如果棋子摔碎了,就不能繼續用這個棋子進行測試了)。

1 <= n <= 10^18, 1 <= m <= 64

由於本題的原題目背景中的棋子是「鷹蛋」,而蛋比棋子說起來方便,所以下文中都用蛋描述。

注意一下:乙個蛋如果沒有碎的話,還可以繼續用!

我們考慮定義 $dp[i][j]$ 表示使用 $i$ 個蛋,拋 $j$ 次,能夠確定的樓層總數。

我們有 $dp[i][j]=dp[i][j-1]+dp[i-1][j-1]+1$ 。為什麼是這個式子?我們分三種情況論述:

1. 首先可以確定當前位置。 對於當前dp值的貢獻:1

2. 如果蛋沒碎,那麼顯然這個位置以下的全部都不會碎。我們要用 $i$ 個蛋拋 $j-1$ 次來確定這個位置以上能確定的樓層數,即 $dp[i][j-1]$ 。

3. 如果蛋碎了,那麼顯然這個位置以上的全部都會碎。我們要用剩餘的 $i-1$ 個但拋 $j-1$ 次來確定這個位置以下能確定的樓層數,即 $dp[i-1][j-1]$ 。

由於當 $m\leq 2$ 的時候,拋的次數可能非常多,我們把它特判掉。

當 $m\leq 3$ 的時候,拋的次數很少了。

我們可以 $dp$ 預處理出來,最後 lower_bound 一下就可以了。由於存在很多無用的狀態(dp值過大),所以我們可以用 vector 來只存一下有用狀態。

#include using namespace std;

typedef long long ll;

const ll inf=1000000000000000001ll,n=2e6;

int t;

ll n,m;

vector dp[70];

int main()

while (t--)

else

printf("%d\n",lower_bound(dp[m].begin(),dp[m].end(),n)-dp[m].begin());

} return 0;

}

51Nod1306 高樓和棋子

題目看這裡 乙個非常好的逆向思維題 都是套路233 如果直接做發現其實可以做,但是資料範圍太大不能過了,具體做法參考這裡 開始正文 首先,我們設f i,j 表示f i,j 表 示在有i個棋子的情況下,扔j次能保證測出的樓層最高是多少,顯然如果n可以被測出,那麼n 1也可以被測出 於是考慮一下最優策略...

51Nod1306 高樓和棋子

題目看這裡 乙個非常好的逆向思維題 都是套路233 如果直接做發現其實可以做,但是資料範圍太大不能過了,具體做法參考這裡 開始正文 首先,我們設f i,j 表示 role presentation f i j 表 示f i j 表 示在有i個棋子的情況下,扔j次能保證測出的樓層最高是多少,顯然如果n...

51nod 貪心入門

有若干個活動,第i個開始時間和結束時間是 si,fi 活動之間不能交疊,要把活動都安排完,至少需要幾個教室?分析 能否按照之一問題的解法,每個教室安排盡可能多的活動,即按結束時間排序,再貪心選擇不衝突的活動,安排乙個教室之後,剩餘的活動再分配乙個教室,繼續貪心選擇 反例 a 1,2 b 1,4 c ...