感觉是这场唯一比较有趣的题?
首先明确一点:先手只会选 \(2\) 个数,因为数多了 \(\gcd\) 会变小,而且对方的 \(\text{and}\) 会变大。
所以对于某一位,若 \(0\) 的个数 \(\ge 3\) 那么对方的按位与这一位一定是 \(0\)。
所以若 \(0\) 的个数 \(\le 2\),那么可能会选这一位是 \(0\) 的,导致对方的按位与这一位是 \(1\)。把它们加入一个集合 \(S\) 中。
对每一位做这一步后 \(S\) 的大小为 \(O(\log V)\)。枚举 \(S\) 中的每个元素,再 \(O(n)\) 枚举另外一个选什么,\(O(\log V)\) check 一下即可(\(O(\log V)\) 是因为要算 \(\gcd\))。
令 \(T = \{1, 2, \ldots, n\} \setminus S\)。此时还没有考虑选 \(T\) 中的数。但是因为选 \(T\) 中的任意两个数,剩下的数的按位与都等于原序列的按位与,所以我们只可能选 \(T\) 中两两 \(\gcd\) 最大的两个数,设它们为 \(a_x, a_y\)。特殊考虑一下它们即可。
总时间复杂度 \(O(n \log^2 V)\)。
code
// Problem: H. GCD is Greater
// Contest: Codeforces - Codeforces Round 935 (Div. 3)
// URL: https://codeforces.com/contest/1945/problem/H
// Memory Limit: 512 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 400100;
const int N = 400000;
const int logn = 21;
int n, m, a[maxn], K, b[maxn], f[logn][maxn];
bool vis[maxn];
vector<int> di[maxn];
inline void init() {
for (int i = 1; i <= N; ++i) {
for (int j = i; j <= N; j += i) {
di[j].pb(i);
}
}
}
inline int qand(int l, int r) {
if (l > r) {
return -1;
}
int k = __lg(r - l + 1);
return (f[k][l] & f[k][r - (1 << k) + 1]);
}
inline int query(int x, int y) {
if (x > y) {
swap(x, y);
}
return qand(1, x - 1) & qand(x + 1, y - 1) & qand(y + 1, n);
}
void solve() {
scanf("%d%d", &n, &m);
K = 0;
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
K = max(K, a[i]);
vis[i] = 0;
f[0][i] = a[i];
}
for (int j = 1; (1 << j) <= n; ++j) {
for (int i = 1; i + (1 << j) - 1 <= n; ++i) {
f[j][i] = (f[j - 1][i] & f[j - 1][i + (1 << (j - 1))]);
}
}
for (int i = 1; i <= K; ++i) {
b[i] = 0;
}
vector<int> S;
for (int i = 18; ~i; --i) {
vector<int> T;
for (int j = 1; j <= n; ++j) {
if ((~a[j]) & (1 << i)) {
T.pb(j);
}
}
if ((int)T.size() <= 2) {
for (int i : T) {
S.pb(i);
vis[i] = 1;
}
}
}
for (int i = 1; i <= n; ++i) {
if (!vis[i]) {
for (int j : di[a[i]]) {
++b[j];
}
}
}
for (int i = K; i; --i) {
if (b[i] >= 2) {
vector<int> T;
for (int j = 1; j <= n && (int)T.size() < 2; ++j) {
if (a[j] % i == 0 && !vis[j]) {
T.pb(j);
}
}
int x = __gcd(a[T[0]], a[T[1]]), y = query(T[0], T[1]);
if (x > y + m) {
printf("YES\n2 %d %d\n%d ", a[T[0]], a[T[1]], n - 2);
for (int k = 1; k <= n; ++k) {
if (k == T[0] || k == T[1]) {
continue;
}
printf("%d ", a[k]);
}
putchar('\n');
return;
}
break;
}
}
sort(S.begin(), S.end());
S.erase(unique(S.begin(), S.end()), S.end());
for (int i : S) {
for (int j = 1; j <= n; ++j) {
if (i == j) {
continue;
}
int x = __gcd(a[i], a[j]), y = query(i, j);
if (x > y + m) {
printf("YES\n2 %d %d\n%d ", a[i], a[j], n - 2);
for (int k = 1; k <= n; ++k) {
if (i == k || j == k) {
continue;
}
printf("%d ", a[k]);
}
putchar('\n');
return;
}
}
}
puts("NO");
}
int main() {
init();
int T = 1;
scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}