CF939F Cutlet 單調佇列優化DP

2022-03-25 22:29:00 字數 1608 閱讀 6912

題目大意:要煎一塊有兩個面的肉,只能在一段k不相交的時間段$[l_,r_]$內翻轉,求$2*n$秒後,保證兩個面煎的時間一樣長時,需要最少的翻轉次數,$n<=100000$,$k<=100$

神仙單調佇列優化$dp$, [noi2005]瑰麗華爾茲 也有類似的壓時間段的套路,但這道題可比那道題難多了。

樸素$o(n^2)$的$dp$沒什麼好說的,我們要想辦法把它優化成$o(nk)$的

定義$f[i][j]$表示第$i$個時間段內,朝上的面(現在沒被煎的)被煎的時間是$j$

1.觀察翻轉的過程,貌似在乙個連續的時間段內翻轉2次以上就是沒有意義的 ,因為可以翻過去再翻回來

2.貌似並不一定要在整數時間翻轉,但這種情況只在翻轉1次的情況下有意義,所以整體把時間*2

然後,分情況討論$dp$轉移

1.翻0次,朝上的面被煎的時間不變,$f[i][j]=f[i-1][j]$,無需任何優化

2.翻2次,朝上的面被至多額外煎$r_+l_$秒,列舉上一次當前面被煎的時間$k$,可得$f[i][j]=min(f[i][k])+2\;(k<=j)$

對於這種情況,正序列舉$j$,單調佇列優化$dp$即可,$j-k>r_+l_$的彈出佇列

3.翻1次,原來朝上的面被翻到了下面,設現在的上面是$a$面,下面是$b$面,則$a$面被煎了$j$秒,$b$面被煎了$r_-j$秒

那麼上一次$a$面被煎的時間是$k$,此時$a$面朝下,朝上的面是$b$面,被煎的時間是$r_-k$,可得$f[i][j]=min(f[i-1][r_-k])+1$

因為是$-k$,要倒序列舉$j$,同樣用單調佇列優化,$k-j>r_+l_$彈出佇列即可

雖然空間能開下$o(nk)$,但用滾動陣列跑得飛快

1 #include 2 #include 3 #include 4

#define n 205

5#define m 401000

6#define dd double

7#define inf 0x3f3f3f3f

8#define rint register int

9using

namespace

std;

1011

intn,k,cnt;

12int

l[n],r[n],t[n];

13int f[2

][m],que[m];

1415

intmain()

1622 memset(f,0x3f,sizeof

(f));

23 f[0][0]=0;int now=1,pst=0

;24 n<<=1;25

for(int i=1;i<=cnt;i++)

2641 hd=1,tl=0;42

for(rint j=t[i];j>=0;j--)

4351

swap(now,pst);

52}

53if(f[pst][n]==inf) printf("

hungry\n");

54else printf("

full\n%d\n

",f[pst][n]);

55return0;

56 }

CF91B Queue(單調佇列 二分)

這題比較經典,我們想要求比他小的最遠的點 因此我們發現,如果乙個點比他前面的點大還比他近,說明這個點永遠不會作為答案 因此我們就可以維護乙個單調佇列,之後二分找到第乙個大於等於他的位置在哪,之後這個位置的前乙個就是答案 includeusing namespace std typedef long ...

cf 1077f2 基礎dp 單調雙向佇列

n個數ai組成的序列,在這n個數中選x個數,保證任意k個相連的數有1個數被選中。求這n個數中選x個數的最大和。n 5000。1.dp i j 表示前i個數選j個數且其中包括第i個數的最大和。2.dp i j max dp m j 1 a j m max 0 i k i 3.這道題因為n的原因o n ...

NOIP2017模擬賽 龍珠(dp 單調佇列優化)

你得到了乙個龍珠雷達,它會告訴你龍珠出現的時間和地點。龍珠雷達的畫面是一條水平的數軸,每乙個視窗時間,數軸的某些點上會出現同一種龍珠,每當你獲得其中一顆龍珠,其它龍珠就會消失。下乙個視窗時間,數軸上又會出現另一種龍珠。總共有n個視窗時間,也就是總共有n種龍珠。假設你會瞬間移動,你從數軸的x點移動到y...