绿色通道

题目链接:http://codevs.cn/problem/3342/

 

 题解:

  求最大值最小? 考虑二分答案。

  在[1,n]中二分出满足要求的最小的t。

  设f[i]表示在前i份作业中做第i份作业且前i份作业满足最大不做区间小于等于二分出的t的最小时间花费。

  所以f[i] = min{f[j]}+time[i] (i-t-1<=j<i)

  复杂度O(n^2),有些爆炸。

  用单调队列可以优化至O(n*logn),满足数据要求。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<queue>
 5 #define LL long long
 6 #define RI register int
 7 using namespace std;
 8 const int INF = 0x7ffffff ;
 9 const int N = 50000 + 10 ;
10 
11 inline int read() {
12     int k = 0 , f = 1 ; char c = getchar() ;
13     for( ; !isdigit(c) ; c = getchar())
14       if(c == '-') f = -1 ;
15     for( ; isdigit(c) ; c = getchar())
16       k = k*10 + c-'0' ;
17     return k*f ;
18 }
19 int n, t ; int hh[N], f[N] ;
20 deque<int>q1, q11 ;
21 
22 inline bool check(int mm) {
23     q1.clear(), q11.clear() ;
24     for(int i=1;i<=mm+1;i++) {
25         f[i] = hh[i] ;
26         while(q1.size() && q1.back() >= f[i]) q1.pop_back(), q11.pop_back() ;
27         q1.push_back(f[i]), q11.push_back(i) ;
28     }
29     for(int i=mm+2;i<=n;i++) {
30         int sdd = i-mm-1 ;
31         while(q11.size() && q11.front() < sdd) q1.pop_front(), q11.pop_front() ;
32         f[i] = hh[i] + q1.front() ;
33         while(q1.size() && q1.back() >= f[i]) q1.pop_back(), q11.pop_back() ;
34         q1.push_back(f[i]), q11.push_back(i) ;
35     }
36     for(int i=n-mm;i<=n;i++) {
37         if(f[i] <= t) return 1 ;
38     } return 0 ;
39 }
40 
41 int main() {
42     n = read(), t = read() ;
43     for(int i=1;i<=n;i++) hh[i] = read() ;
44     int l = 1, r = n, ans = INF ;
45     while(l <= r) {
46         int mid = l+r>>1 ;
47         if(check(mid)) {
48             ans = min(ans,mid) ; r = mid-1 ;
49         }
50         else l = mid+1 ;
51     }
52     printf("%d",ans) ;
53     return 0 ;
54 } 
View Code
原文地址:https://www.cnblogs.com/zub23333/p/8604324.html