滑動視窗 二分 P3957 跳房子

2022-05-27 19:06:11 字數 1273 閱讀 9281

* 思路:$dp_i$表示到第$i$個格仔的最大得分,仔細思考後發現$f_i$只能從他之前一段區間內的最大$f_i$轉移過來,且隨著區域的後移不斷改變,滑動視窗維護再二分答案就好了。

***實現:

滑動視窗的活動範圍:$max$($d-len$,1)$\to$$d+len$

滑動視窗的移動:當最大值的位置超過了他能跳到的最遠距離,則head++,視窗右移,另外如果我隊尾的元素小於我現在加入的元素,那麼隊尾元素對答案沒有貢獻,彈出就好了,則tail--

while (head<=tail&&dp[now]>=dp[q[tail]]) tail--;

q[++tail]=now,now++;

while (head<=tail&&x[q[head]]

注意如果當前點不能到達要直接跳過

if (dp[now]<=-1e9)

二分答案:按公升序的花費二分,如果當前花費無法滿足總和大於$k$,那麼前面的也一定不滿足,則找右區間,如果當前花費滿足總和大於$k$,那麼後面的也一定滿足,則找左區間,滿足二分的單調性和區域性捨棄性。

while (l完整**:

1 #include 2 #include 3 #include 4

#define int long long

5using

namespace

std;

6const

int maxn=5e5+10;7

intn,d,k;

8int

x[maxn],s[maxn],q[maxn],dp[maxn];

9bool tag=0;10

bool solve(int

len)

15while (head<=tail&&dp[now]>=dp[q[tail]]) tail--;

16 q[++tail]=now,now++;17}

18while (head<=tail&&x[q[head]];

19if (head<=tail) dp[i]=dp[q[head]]+s[i];

20else dp[i]=-1e9;

21if (dp[i]>=k) return1;

22}23return0;

24}25signed main()

34if (tag) printf("

%lld\n

",r);

35else printf("

-1\n");

36return0;

37 }

題解 P3957 跳房子

題目鏈結 題目大意 給定 n 個格仔離原點距離以及權值,初始單次移動距離只能為 d 你可以花費 g 枚金幣使得單次移動距離變為 max d g,1 d g 內任意整數,問獲得權值至少為 k 最少需要花費多少枚金幣 單調佇列 分析 顯而易見答案具有單調性,因為花費金幣越多機械人越靈活,花費金幣少的可行...

P3957 跳房子 單調佇列,dp,二分

這就是之前普及組的第四題 有n個格仔,每個格仔有價值。機械人有固定的跳躍距離d,用k個金幣改進的話,就可以讓跳躍距離在d k到d k之間,不過至少要往前跳1個單位長度,每次都必須跳到格仔上。要求超過需要的價值求需要消耗的最少金幣。二分所需金幣數然後 dp,f i f i 表示跳到第i個格仔最大價值,...

洛谷P3957 跳房子

普及組的題。我不會。題目 思路很簡單,就是二分答案 dp 單調佇列 線段樹也可以 但是要注意細節,乙個細節錯了,一半分數就沒了。引用洛谷上某大佬的一段話 發現答案的可行區間是單調的,所以二分答案,容易推出f i 表示到達第i個格仔的最大值,列舉上一步跳了多少來轉移 然後仔細觀察可以發現對於乙個狀態,...