[CODEFORCES 1501C Going Home](https://codeforces.com/contest/1501/problem/C)
=
## 題目大意
給整數數列 $a$
找出**兩兩相異** $x, y, z, w$ 滿足 $a_x + a_y = a_z + a_w$
> 即 $x \not= y \not= z \not= w, y \not= w \not= x \not= z$
## 輸入
$n$ $(4 \le n \le 2\cdot 10^5)$,表示 $a$ 長度
$a_1, a_2, \cdots, a_n$ $(1 \le a_i \le 2.5\cdot 10^6)$
## 輸出
`YES` 表示存在解,反之 `NO`
若存在解,接著輸出一組 $x, y, z, w$
## 解法
令任意兩數相加 $S_{i,j} = a_i + a_j$
對於 $S_{z, w}$ 希望找到兩數 $a_x, a_y$ 使得 $S_{z, w} = S_{x, y}$
但 $x, y, z, w$ 有可能不滿足兩兩相異,所以得討論怎樣的情況能滿足這個條件
對某數 $S$,以**點**表示數列下標,**邊** $(x, y) \in E$ 表示 $S = a_x + a_y$,可觀察到圖:
- $E \ge 2$ 條邊,所有邊**沒有共同點**,則所有邊的點都兩兩相異
- $E \ge 2$ 條邊,所有邊**有共同點** $x$ 除了**某邊沒有** $x$,則該邊與某條邊的點兩兩相異
- $E \ge 4$ 條邊,所有邊**有共同點** $x$,則取 4 個 $x$ 的鄰點 $i_1, i_2, i_3, i_4$ 會滿足 $a_{i_1} + a_{i_2} = a_{i_3} + a_{i_4}$
> 因為 $a_{i_1} = a_{i_2} = a_{i_3} = a_{i_4}$
也就是說至多找出 **4 組相異[^diff]的數對**使得 $S_{i_1, j_1} = S_{i_2, j_2} = S_{i_3, j_3} = S_{i_4, j_4}$ 就有解了
兩數相加範圍 $[2\cdot\min\{a\}, 2\cdot\max\{a\}]$,總共 $N = 2\cdot\max\{a\} - 2\cdot\min\{a\} + 1$ 種相加後的和
因此根據**鴿籠原理**,枚舉 $3 \cdot N + 1$ 組相異數對,**至少**會有 4 組的和是**相同**的
所以至多只需枚舉 $\mathcal{O}(3\cdot N + 1) = \mathcal{O}(a_i)$ 個數對就能確定有沒有解
```cpp
#include<bits/stdc++.h>
using namespace std;
int constexpr maxn = 2e5 + 10;
int constexpr maxa = 25e5 + 10;
int n, a[maxn];
int main()
{
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
pair<int, int> vis[maxa*2] {};
for(int i = 1; i <= n; i++)
for(int j = i+1; j <= n; j++) {
int sum = a[i] + a[j];
auto& [_i, _j] = vis[sum];
if(!_i) _i = i, _j = j;
else if(_i != i && _i != j && _j != i && _j != j) {
puts("YES");
printf("%d %d %d %d\n", _i, _j, i, j);
return 0;
}
}
puts("NO");
return 0;
}
```
[^diff]: $(x, y)$, $(z, w)$ 相異表示存在 $i \in (x, y), j \in (z, w)$ 有 $i \not= j$