Description
你有 \(n\) 根棍子,從 \(1\) 到 \(n\) 編號。第 \(i\) 根棍子的長度是 \(a_i\)。
你需要回答 \(q\) 個問題。在每個查詢中,你會得到兩個整數 \(l\) 和 \(r\)(\(1 \le l < r \le n,r − l + 1 \ge 6\))。確定是否可以從編號為 \(l\) 到 \(r\) 的棒中選擇 \(6\) 個不同的棒,形成 \(2\) 個非退化三角形。
邊長為 \(a\)、\(b\) 和 \(c\) 的三角形稱為非退化三角形,當且僅當 \(a<b+c,b<a+c,c<a+b\)。
Solution
先考慮什麼樣的序列存在至少一個三角形。容易發現把序列排序後,如果存在三角形,則必存在一個長度為 \(3\) 的連續區間滿足條件。
而如果不存在,則一定滿足 \(a_i\geq a_{i-1}+a_{i-2}\)。經過計算,這樣的序列長度一定不超過 \(45\),即長度不小於 \(45\) 的序列一定存在至少一個三角形。
回到這個題。利用上面那個結論可以得出序列長度 \(\geq 48\) 時一定存在答案,因為這裡至少存在一個三角形,去掉這個三角形後還剩 \(45\) 個數,所以存在第二個。
於是 \(r-l+1\geq 48\) 時必然有解,現在需要判斷 \(r-l+1\leq 47\) 時是否有解。
同樣是先排序,把所有形如 \((i,i+1,i+2)\) 且滿足 \(a_i+a_{i+1}>a_{i+2}\) 的數對拿出來,如果存在兩個數對不相交則一定有解。
如果不存在則說明最終的兩個三角形是相交的,就像 \((1,2,4),(3,5,6)\) 這種。注意到這時選的 \(6\) 個數如果不是連續的 \(6\) 個則調整成連續的一定更優,所以只需要對於所有連續的 \(6\) 個數暴力判斷即可。
時間複雜度:\(O(n\log V\log\log V)\)。
Code
#include <bits/stdc++.h>
// #define int int64_t
const int kMaxN = 1e5 + 5;
int n, q;
int a[kMaxN];
bool check(int64_t x, int64_t y, int64_t z) {
return x + y > z && x + z > y && y + z > x;
}
bool check(int l, int r) {
std::vector<int> vec;
for (int i = l; i <= r; ++i) vec.emplace_back(a[i]);
std::sort(vec.begin(), vec.end());
int mi = 1e9;
for (int i = 2; i < (int)vec.size(); ++i) {
if (check(vec[i - 2], vec[i - 1], vec[i])) {
if (i - 2 > mi) return 1;
if (mi == 1e9) mi = i;
}
}
for (int i = 0; i + 5 < (int)vec.size(); ++i) {
if (check(vec[i], vec[i + 1], vec[i + 2]) && check(vec[i + 3], vec[i + 4], vec[i + 5])) return 1;
if (check(vec[i], vec[i + 1], vec[i + 3]) && check(vec[i + 2], vec[i + 4], vec[i + 5])) return 1;
if (check(vec[i], vec[i + 1], vec[i + 4]) && check(vec[i + 2], vec[i + 3], vec[i + 5])) return 1;
if (check(vec[i], vec[i + 1], vec[i + 5]) && check(vec[i + 2], vec[i + 3], vec[i + 4])) return 1;
if (check(vec[i], vec[i + 2], vec[i + 3]) && check(vec[i + 1], vec[i + 4], vec[i + 5])) return 1;
if (check(vec[i], vec[i + 2], vec[i + 4]) && check(vec[i + 1], vec[i + 3], vec[i + 5])) return 1;
if (check(vec[i], vec[i + 2], vec[i + 5]) && check(vec[i + 1], vec[i + 3], vec[i + 4])) return 1;
if (check(vec[i], vec[i + 3], vec[i + 4]) && check(vec[i + 1], vec[i + 2], vec[i + 5])) return 1;
if (check(vec[i], vec[i + 3], vec[i + 5]) && check(vec[i + 1], vec[i + 2], vec[i + 4])) return 1;
if (check(vec[i], vec[i + 4], vec[i + 5]) && check(vec[i + 1], vec[i + 2], vec[i + 3])) return 1;
}
return 0;
}
void dickdreamer() {
std::cin >> n >> q;
for (int i = 1; i <= n; ++i) std::cin >> a[i];
for (int i = 1; i <= q; ++i) {
int l, r;
std::cin >> l >> r;
if (r - l + 1 >= 48) std::cout << "YES\n";
else std::cout << (check(l, r) ? "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();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}