CF1991F Triangle Formation 題解

下蛋爷發表於2024-09-07

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;
}

相關文章