题意
给定 n n n个点,第 i i i个点的值为 a i ( 1 ≤ a i ≤ n ) a_i(1 \le a_i \le n) ai(1≤ai≤n),给定 n − 1 n-1 n−1次操作,第 x x x次 ( 1 ≤ x ≤ n − 1 ) (1 \le x \le n-1) (1≤x≤n−1)操作选择两个点 a u a_u au和 a v a_v av,如果 x ∣ a b s ( a u − a v ) x |abs(a_u-a_v) x∣abs(au−av)则可以将这两个点连起来,问 n − 1 n-1 n−1次操作后是否能连接所有的点并输出每条边
思路
- 转化条件: x ∣ a b s ( a u − a v ) x |abs(a_u-a_v) x∣abs(au−av),即 a u ≡ a v ( m o d x ) a_u\equiv a_v(mod \ x) au≡av(mod x),那么每次连边的时候只要找两个模x结果相同的数即可
- 抽屉原理:当进行最后一次即第 n − 1 n-1 n−1次操作时,由于一共有 n n n个数且这 n n n个数的范围为1~n,那么每个数模 n − 1 n-1 n−1后最多有 n − 1 n-1 n−1个结果 ( 0 , 1 , . . . , n − 3 , n − 2 ) (0,1,...,n-3,n-2) (0,1,...,n−3,n−2)。 n n n个数, n − 1 n-1 n−1个结果,说明至少有两个数他们模 n − 1 n-1 n−1的结果是一样的
- 于是,从第 n − 1 n-1 n−1次操作开始往前枚举,每次连接模 x x x的结果相同的两个点即可,当然已经属于同一个连通块的两个点是不能连接的,可以使用并查集来判断是否属于同一个连通块
代码
/* \/\ \ /\ \
\ \ \/'/' __ __\ \ \ __ ___
\ \ , < /\ \/\ \\ \ \ __ /'__`\/' _ `\
\ \ \\`\\ \ \_\ \\ \ \L\ \/\ __//\ \/\ \
\ \_\ \_\/`____ \\ \____/\ \____\ \_\ \_\
\/_/\/_/`/___/> \\/___/ \/____/\/_/\/_/
/\___/
___ ___ \/__/ qq: 2729269812
/' __` __`\ email: kkkylen@qq.com
/\ \/\ \/\ \ ___ __ __
\ \ \ \ \ \ \ / __`\/\ \/\ \
\ \ \ \ \ \ \/\ \L\ \ \ \_\ \
\ \ \ \ \ \ \ \____/\ \____/
\/_/\/_/\/_/\/___/ \/__*/
#include<bits/stdc++.h>
#define x first
#define y second
#define endl '\n'
#define int long long
using namespace std;
void KyLen() {
int n;
cin >> n;
vector<int> a(n+1), p(n+1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
p[i] = i;
}
function<int(int)> find = [&] (int x) {
return p[x] == x ? x : p[x] = find(p[x]);
};
auto merge = [&] (int a, int b) {
p[find(a)] = find(b);
};
vector<pair<int,int>> ans;
for (int mod = n - 1; mod >= 1; mod--) {
map<int,int> m;
for (int i = 1; i <= n; i++) {
int cur = m[a[i] % mod];
if (cur == 0) {
m[a[i] % mod] = i;
} else if (find(cur) != find(i)) {
merge(cur,i);
ans.push_back({cur,i});
break;
}
}
}
cout << "YES" << endl;
for (auto it = ans.rbegin(); it != ans.rend(); it++) {
cout << it -> x << ' ' << it -> y << endl;
}
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int T; cin >> T; while(T--) KyLen();
return 0;
}