1. 程式人生 > >CF939F Cutlet (單調佇列優化DP)

CF939F Cutlet (單調佇列優化DP)

題目大意:要煎一塊有兩個面的肉,只能在一段k不相交的時間段$[l_{i},r_{i}]$內翻轉,求$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_{i}+l_{i}$秒,列舉上一次當前面被煎的時間$k$,可得$f[i][j]=min(f[i][k])+2\;(k<=j)$

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

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

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

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

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

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define N 205
 5 #define M 401000
 6 #define dd double
 7 #define inf 0x3f3f3f3f
 8 #define rint register int 
 9 using namespace std;
10 11 int n,K,cnt; 12 int l[N],r[N],t[N]; 13 int f[2][M],que[M]; 14 15 int main() 16 { 17 scanf("%d%d",&n,&K); 18 for(int i=1;i<=K;i++){ 19 scanf("%d%d",&l[i],&r[i]); 20 t[++cnt]=l[i]<<1,t[++cnt]=r[i]<<1; 21 } 22 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++) 26 { 27 if(i&1) continue; 28 int hd=1,tl=0; 29 for(rint j=0;j<=t[i];j++) 30 f[now][j]=inf; 31 for(rint j=0;j<=t[i];j++) 32 { 33 f[now][j]=min(f[now][j],f[pst][j]); 34 while(hd<=tl&&f[pst][j]<=f[pst][que[tl]]) 35 tl--; 36 que[++tl]=j; 37 while(hd<=tl&&j-que[hd]>t[i]-t[i-1]) 38 hd++; 39 f[now][j]=min(f[now][j],f[pst][que[hd]]+2); 40 } 41 hd=1,tl=0; 42 for(rint j=t[i];j>=0;j--) 43 { 44 while(hd<=tl&&f[pst][t[i]-j]<=f[pst][t[i]-que[tl]]) 45 tl--; 46 que[++tl]=j; 47 while(hd<=tl&&que[hd]-j>t[i]-t[i-1]) 48 hd++; 49 f[now][j]=min(f[now][j],f[pst][t[i]-que[hd]]+1); 50 } 51 swap(now,pst); 52 } 53 if(f[pst][n]==inf) printf("Hungry\n"); 54 else printf("Full\n%d\n",f[pst][n]); 55 return 0; 56 }