Codeforces 1029B. Creating the Contest 動態規劃O(nlogn)解法 及 單調隊列O(n)解法
阿新 • • 發佈:2019-04-17
時間復雜度 tin eat build clas problems end -- 組成
題目鏈接:http://codeforces.com/problemset/problem/1029/B
題目大意:從數組a中選出一些數組成數組b,要求 b[i+1]<=b[i]*2
。
一開始想到的是O(n^2)的動態規劃,但是超時了,下面是超時的代碼。
#include <iostream> using namespace std; const int maxn = 200020; int n, a[maxn], f[maxn], res = 0; int main() { cin >> n; for (int i = 0; i < n; i ++) cin >> a[i]; for (int i = 0; i < n; i ++) { f[i] = 1; for (int j = i-1; j >= 0 && a[i] <= 2*a[j]; j --) { f[i] = max(f[i], f[j]+1); } if (f[i] > res) res = f[i]; } cout << res << endl; return 0; }
然後想到的是:
- 二分找最小的滿足a[i]<=a[j]*2的那個j ,O(logn)的時間復雜度
- 線段樹求區間[j,i-1]的最大值,O(logn)的時間復雜度
再加上外層的循環,時間復雜度會降到O(n * logn)。
代碼:
#include <iostream> using namespace std; #define lson l, m, rt << 1 #define rson m+1, r, rt << 1 | 1 const int maxn = 200020; int n, a[maxn], MAX[maxn<<2]; void pushUp(int rt) { MAX[rt] = max(MAX[rt<<1] , MAX[rt<<1|1]); } void build(int l, int r, int rt) { if (l == r) { MAX[rt] = 0; return; } int m = (l+r) >> 1; build(lson); build(rson); pushUp(rt); } void update(int p, int val, int l, int r, int rt) { if (l == r) { MAX[rt] = val; return; } int m = (l + r) >> 1; if (p <= m) update(p, val, lson); else update(p, val, rson); pushUp(rt); } int query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) { return MAX[rt]; } int m = (l + r) >> 1; int tmp = 0; if (L <= m) tmp = query(L, R, lson); if (R >= m+1) tmp = max(tmp, query(L, R, rson)); return tmp; } int findL(int i) { return lower_bound(a, a+n+1, (a[i]+1)/2) - a; } int main() { cin >> n; build(1, n, 1); for (int i = 1; i <= n; i ++) cin >> a[i]; for (int i = 1; i <= n; i ++) { int L = findL(i); int val; if (L >= i) val = 1; else { val = query(L, i-1, 1, n, 1) + 1; } update(i, val, 1, n, 1); } cout << query(1, n, 1, n, 1) << endl; return 0; }
然後是O(n)的單調隊列解法。
代碼:
#include <iostream> using namespace std; const int maxn = 200020; int n, a[maxn], MAX[maxn]; int st = 0, ed = 0, sum = 0; int que[maxn]; // que存放id,id對應的最大長度是MAX[id] void test() { cout << "[test]" << endl; for (int i = 1; i <= n; i ++) { cout << i << ": " << MAX[i] << endl; } } int main() { cin >> n; for (int i = 1; i <= n; i ++) cin >> a[i]; int j = 1; for (int i = 1; i <= n; i ++) { while (j < i && !( a[i] <= 2 * a[j] )) { j ++; } while (st < ed && que[st] < j) st ++; if (st == ed) { MAX[i] = 1; } else { MAX[i] = MAX[ que[st] ] + 1; } sum = max(sum , MAX[i]); while (st < ed && MAX[ que[st] ] <= MAX[i]) { st ++; } que[ed++] = i; } // test(); cout << sum << endl; return 0; }
Codeforces 1029B. Creating the Contest 動態規劃O(nlogn)解法 及 單調隊列O(n)解法