Description
给定一个长度为 n 的整数数组 a。
判断是否存在一种元素排列 b,使得对于每个 2≤i≤n−1,都满足条件 bi−1+bi+1≥2⋅bi。
本题中,每个测试点包含多组输入数据。你需要对每组数据独立求解。
∑n≤3×105。
Solution
先把 ai 排序,那么问题可以看成将 a2,a3,…,an 划分成两个集合,每个集合分别和 a1 构成的序列都是上凸的。
考虑 dp。
设 fi,b,c,d 表示扫了前 i 个数,第一个集合末尾为 ai 和 ab,第二个集合末尾为 ac 和 ad。直接转移是 O(n4) 的。
注意到 b,c 中至少有一个是 i−1,所以状态数变为 O(n3)。
不妨设 b=i−1,那么固定 c 之后,一定是让 d 越大越好,所以可以改变状态,fi,c 表示满足条件的状态 (i,i−1,c,d) 的最大的 d。
如果 c=i−1,则一定满足 b=i−2 或者 d=i−2,这两种状态同样只需要记录最大的第四者,所以这里只有两种状态,容易分讨转移。
考虑 b=i−1 怎么转移。
- i+1 放在第一个集合:即如果 ai+1+ai−1≥2ai,则转移到 (i+1,i,c,d)。
- i+1 放在第二个集合:如果 ai+1+ad≥2ac,转移到 (i,i−1,i+1,c)。
观察第二种转移,容易想到维护一个 (2ac−ad,c) 的集合,可以用动态开点线段树做,不过也可以用 set 维护一个两维分别递增的集合,只有这个集合内的数是有用的,插入时简单维护即可。而第一种转移的意思就是要不要清空 set,同样容易维护。
时间复杂度:O(nlogn)。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| #include <bits/stdc++.h>
#define int int64_t
const int kMaxN = 3e5 + 5;
int n; int a[kMaxN]; std::set<std::pair<int, int>> st;
void ins(int c, int d) { if (c == -1 || d == -1) return; std::pair<int, int> p = {2 * a[c] - a[d], c}; auto it = st.lower_bound({p.first, 0}); for (; it != st.end() && it->second < c;) { st.erase(it); it = st.lower_bound({p.first, 0}); } if (it != st.end() && it->first == p.first && it->second > c) return; if (it != st.begin()) { --it; if (it->second < c) st.emplace(p); } else { st.emplace(p); } }
int get(int x) { auto it = st.lower_bound({a[x] + 1, 0}); if (it != st.begin()) return prev(it)->second; else return -1; }
void dickdreamer() { std::cin >> n; for (int i = 1; i <= n; ++i) std::cin >> a[i]; st.clear(); std::sort(a + 1, a + 1 + n); a[0] = 1e18, a[++n] = a[1]; std::sort(a + 1, a + 1 + n); int d1 = 0, d2 = 0; for (int i = 2; i <= n - 1; ++i) { int _d1 = -1, _d2 = -1; _d2 = std::max(_d2, get(i + 1)); if (a[i + 1] + a[i - 1] < 2 * a[i]) st.clear(); if (~d1) { if (a[i + 1] + a[i - 2] >= 2 * a[i]) ins(i - 1, d1); if (a[i + 1] + a[d1] >= 2 * a[i - 1]) _d1 = std::max(_d1, i - 2); } if (~d2) { if (a[i + 1] + a[d2] >= 2 * a[i]) ins(i - 1, i - 2); if (a[i + 1] + a[i - 2] >= 2 * a[i - 1]) _d1 = std::max(_d1, d2); } d1 = _d1, d2 = _d2; } std::cout << ((~d1 || ~d2 || st.size()) ? "YES\n" : "NO\n"); }
int32_t main() { #ifdef ORZXKR freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0); int T = 1; std::cin >> T; while (T--) dickdreamer(); return 0; }
|