#10181. 「一本通 5.5 练习 2」绿色通道
二分+$dp$(与跳房子类似)
二分答案(窗口大小),$dp$确定是否可行
$f[i]$表示到$i$($i$选)花的最少时间
$$f[i] = min_{j\in[i-d-1,i-1]}\left \{ f[j] \right \}+a[i]$$
$d$为二分的答案
注意统计是要$f[n+1]>t$才$return\;0$
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #define ll long long 6 using namespace std; 7 8 template <typename T> void in(T &x) { 9 x = 0; T f = 1; char ch = getchar(); 10 while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();} 11 while( isdigit(ch)) {x = 10 * x + ch - 48; ch = getchar();} 12 x *= f; 13 } 14 15 template <typename T> void out(T x) { 16 if(x < 0) x = -x , putchar('-'); 17 if(x > 9) out(x/10); 18 putchar(x%10 + 48); 19 } 20 //------------------------------------------------------- 21 22 const int N = 5e4+7; 23 int n,t; 24 int a[N],f[N]; 25 int q[N],hd,tl,lst; 26 27 bool chk(int d) { 28 memset(f,0x3f,sizeof(f)); f[0] = 0; 29 hd = 1,tl = 0,lst = 0; int i; 30 for(i = 1;i <= n+1; ++i) { 31 while(lst < i-d-1) ++lst; 32 for(;lst < i; ++lst) { 33 while(hd <= tl && f[q[tl]] > f[lst]) --tl;//debug --tl -> --q[tl] 34 q[++tl] = lst; 35 } 36 while(hd <= tl && q[hd] < i-d-1) ++hd; 37 f[i] = f[q[hd]] + a[i]; 38 //if(f[i] > t) return 0;//debug 39 } 40 if(f[n+1] > t) return 0;//debug 41 return 1; 42 } 43 44 void bs_ans() { 45 int l = 0,r = n,ans; 46 while(l <= r) { 47 int mid = (l+r)>>1; 48 if(chk(mid)) ans = mid,r = mid-1; 49 else l = mid+1; 50 } 51 out(ans); 52 } 53 54 int main() { 55 in(n); in(t); int i; 56 for(i = 1;i <= n;++i) in(a[i]); 57 bs_ans(); 58 return 0; 59 }