// TLE 解法 (時間計算量: O(m*2^n)) C++23 #include // all #pragma GCC optimize ("O3") #pragma GCC target ("arch=x86-64-v3,tune=native") using namespace std; #define MAX_T 1000 #define MAX_N 27 #define MAX_COST 1e8 using NodeIndex = uint8_t; using State = uint8_t; // 与えられた比較交換器ネットワークがソーティングネットワークかどうかをチェック expected, vector> is_sorting_network(const int n, const int m, const vector> &cmps) { assert(2 <= n); assert(1 <= m && cmps.size() == m); for (auto [a, b] : cmps) { // 0-indexed かつ a < b かつ b < n であることを確認 assert(0 <= a && a < b && b < n); } vector state(n, 0); // unused[i] は i 番目の比較交換器が未使用の場合に true // unsorted[i] は全ての比較交換器を通した後 i,(i+1) 番目の要素が昇順でない場合に true vector unused(m, true), unsorted(n - 1, false); uint64_t limit = (uint64_t)1ULL << n; // すべての 0/1 入力パターンを試す (2^n 通り) for (uint64_t bits = 0; bits < limit; ++bits) { // 入力を配列にセット for (int i = 0; i < n; ++i) { state[i] = ((bits >> i) & 1); } // 比較列を適用 for (int j = 0; auto [a, b] : cmps) { if (state[a] > state[b]) { unused[j] = false; swap(state[a], state[b]); } j++; } // 出力がソートされていなければ false for (int k = 0; k < n - 1; ++k) { if (state[k] > state[k + 1]) { unsorted[k] = true; break; } } } // いずれかの入力列でソートされていない場合、 unsorted に true が含まれるのでソーティングネットワークではない if (any_of(unsorted.begin(), unsorted.end(), [](bool x) { return x; })) { // ソートされていない可能性のある位置を返す return unexpected(unsorted); } // すべての入力列においてソートされたならばソーティングネットワーク // 未使用の比較交換器を返す return unused; } int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; assert(1 <= t && t <= MAX_T); // φ = (1 + √5) / 2 : 黄金数 1.618033988749895 double phi = sqrt(1.25) + 0.5; double cost = 0.0; for (int i = 0; i < t; ++i) { int n, m; cin >> n >> m; vector> cmps; assert(2 <= n && n <= MAX_N && 1 <= m && m <= n * (n - 1) / 2); // テストケースのコスト <= MAX_COST cost += m * pow(phi, n); assert(cost <= MAX_COST); // 比較交換器を読み込む vector vec_a, vec_b; for (int j = 0; j < m; ++j) { int a; cin >> a; vec_a.push_back(a); } for (int j = 0; j < m; ++j) { int b; cin >> b; vec_b.push_back(b); } for (int j = 0; j < m; ++j) { int a = vec_a[j], b = vec_b[j]; assert(1 <= a && a < b && b <= n); // 1-indexed to 0-indexed cmps.emplace_back(a - 1, b - 1); } // ソーティングネットワークかどうかをチェック auto is_sorting = is_sorting_network(n, m, cmps); if (is_sorting.has_value()) { auto unused = is_sorting.value(); assert(unused.size() == m); cout << "Yes\n"; // 未使用の比較交換器 j を列挙 cout << count(unused.begin(), unused.end(), true) << '\n'; bool first = true; // 1-indexed for (int j = 1; const auto x : unused) { if (x) { if (!first) { cout << ' '; } cout << j; first = false; } j++; } cout << '\n'; } else { auto unsorted = is_sorting.error(); assert(unsorted.size() == n - 1); cout << "No\n"; // ソートされていない可能性がある位置 k を列挙 cout << count(unsorted.begin(), unsorted.end(), true) << '\n'; bool first = true; // 1-indexed for (int k = 1; const auto x : unsorted) { if (x) { if (!first) { cout << ' '; } cout << k; first = false; } k++; } cout << '\n'; } } return 0; }