绿色通道
题目链接: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 }