小明打聯盟 斜率 單調佇列 優化dp 揹包

2022-09-17 07:30:15 字數 3188 閱讀 7470

題目描述

小明很喜歡打遊戲,現在已知乙個新英雄即將推出,他同樣擁有四個技能,其中三個小技能的釋放時間和固定的傷害值為:

他還有乙個大招,其釋放的時間是乙個區間【l,r】,可以在區間內任意時間點釋放出技能,其如果在l+i時刻釋放技能,其能夠打出的傷害值為:temp+a*i

這裡temp值表示技能的基礎傷害(同時也就是在時刻l釋放技能的傷害值),a是乙個常數。

小明很喜歡研究連招使得在有限的時間內打出最高的傷害,現在他想要在t長度單位時間內打出最高的傷害,問這個最大傷害值。

輸入描述:

本題包含多組資料。

輸入格式為:

tx a

y bz c

l r temp a

資料範圍:

1<=t<=1e5

1<=x,y,z,l,r<=t

l<=r

<=a,b,c,temp,a<=1e5

輸出描述:

輸出包含一行,輸出能夠打出的最高傷害值。
示例1

輸入

8

3 12 3

1 33 3 3 3

輸出

24

備註:

大招:蓄力時間最短l秒,最多r秒。無限次釋放,釋放之後照成的傷害是隨著時間增加的

蓄力l秒釋放能夠造成temp的傷害

蓄力l+1秒釋放能夠造成temp+1*a的傷害

依次類推

題意:小明有三個小技能和乙個大招,每個小技能消耗ai的時間,打出bi的傷害,大招的基礎傷害為temp,基礎時間為l,大招可以蓄力,得到的傷害為temp+(t-l)*a,其中t為大招的時間,上限為r,求總時間為t打出的最高傷害

題解:對於三個小技能可以直接使用普通的揹包dp,而對於大招,如果暴力地把大招時間拆成l,l+1....r,那麼複雜度將是o(n^2),很明顯會超時,而觀察到對大招來說dp[i]=max(dp[j]+temp+a*(i-l-j)),所以對於j>k, 如果 j 相對於k更優,那麼(dp[j]+temp+a*(i-l-j)) - (dp[k]+temp+a*(i-l-k)) > 0,所以有dp[j]-dp[k]>a*(j-k),可以使用斜率優化dp,而由於這裡的a為常數,和 i 無關,所以可以直接知道當前點是否最優,不需要維護凸包,也就是可以不使用斜率優化dp,而使用單調佇列優化dp(斜率優化dp和單調佇列優化dp區別就在插入新點時前者是維護凸包後者是維護單調佇列)

斜率優化dp

#include#include

#include

#include

#include

#include

#include

using

namespace

std;

//#define io_test

#define debug(x) cout

long

long

ll;ll dp[

100005],pq[100005

];int

main()

if(i>=y)

if(i>=z)

if(i>=l)

while(tail-head>=1&&(dp[i-l+1]-dp[pq[tail]])*(pq[tail]-pq[tail-1])>(i-l+1-pq[tail])*(dp[pq[tail]]-dp[pq[tail-1]]))tail--;//

維護凸包

++tail;

pq[tail]=i-l+1

;             }

}printf(

"%lld\n

",dp[t]);

}return0;

}

view code

單調佇列優化dp

1 #include2 #include3 #include4 #include5 #include6 #include7 #include8

using

namespace

std;9//

#define io_test

10#define debug(x) cout<11 typedef long

long

ll;12 ll dp[100005],pq[100005

];13

intmain()

1434

if(i>=y)

37if(i>=z)

40if(i>=l)

45while(tail>=head&&(dp[i-l+1]-dp[pq[tail]])>a*(dp[i-l+1]-dp[pq[tail]]))tail--;//

維護單調佇列

46                 ++tail;

47                 pq[tail]=i-l+1

; 48}49

}50         printf("

%lld\n

",dp[t]);51}

52return0;

53 }

view code

這題還有乙個揹包的寫法,因為大招的傷害和時間的關係是條直線,所以最後的結果一定是若干小技能+若干次不蓄力大招+若干次蓄滿力大招+一次不滿的大招(注意只會使用一次不滿的大招,這點決定了可以直接揹包而不會t掉),也就是說真正需要暴力列舉的大招時間只有一次,也就是那次沒有滿的大招,所以複雜度就是o(n)

1 #include2 #include3 #include4 #include5 #include6 #include7 #include8

using

namespace

std;9//

#define io_test

10#define debug(x) cout<11 typedef long

long

ll;12 ll dp[100005],pq[100005

];13

intmain()

1434

if(i>=y)

37if(i>=z)

40if(i>=l)

43if(i>=r)46}

47for(int i=l;i<=r;i++)

50 printf("

%lld\n

",dp[t]);51}

52return0;

53 }

view code

整理 斜率or單調佇列優化dp

題意 求乙個序列的子區間滿足長度大於k且所有數平均值最大 周源 裡的題。之前有人說周源講的是錯的 其實應該是沒什麼問題的 可以o n 求出 不過這題hdu上的資料不知道怎麼了 反正我在網上找的ac 們全都tle。總之 意思明白就好 反正也是入門題 include include include in...

單調佇列DP 斜率DP

考慮到知識點是單調佇列,考慮怎麼使用單調佇列 首先說明一點,小天使可以選擇當前時刻鋼琴是否移動 並非一次就要一段時間 考慮dp方程,由於每次只能走乙個方向,選擇不了,其實就相當於乙個一維的dp了 以往上 北 為例 t為第t段時間 f t i j max 變形為 f t i j max i 然後把 f...

揹包dp 小明打聯盟

這個題是乙個完全揹包問題,對於大招,我們有三種選擇 l,l i,r l,l i,r l,l i,r,最終的方案中l i l i l i最多出現一次,於是先用前三個 物品 l r 前三個物品 l r 前三個物品 l r這五個物品跑完全揹包,然後用l i l i l i更新一遍dp v dp v dp ...