File size: 15,274 Bytes
1fd0050
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int sub, n;
    cin >> sub >> n;
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    vector<int> all(n);
    iota(all.begin(), all.end(), 1);
    int kk = min(30, n / 3);
    vector<int> seeds;
    int max_trials = 1000;
    for (int trial = 0; trial < max_trials; ++trial) {
        random_shuffle(all.begin(), all.end());
        vector<int> cand(all.begin(), all.begin() + kk);
        vector<int> seq = cand;
        random_shuffle(seq.begin(), seq.end());
        cout << seq.size();
        for (int x : seq) cout << " " << x;
        cout << "\n";
        cout.flush();
        vector<int> res(seq.size());
        for (int &x : res) cin >> x;
        bool good = true;
        for (int b : res) if (b) {
            good = false;
            break;
        }
        if (good) {
            seeds = cand;
            break;
        }
        if (trial == max_trials - 1) {
            // fallback smaller kk
            kk /= 2;
            trial = -1;
        }
    }
    // now seeds has kk independent labels
    vector<deque<int>> chains;
    set<int> known_set;
    for (int s : seeds) {
        chains.emplace_back(deque<int>{s});
        known_set.insert(s);
    }
    int num_chains = chains.size();
    // now extend until done
    while (known_set.size() < n) {
        // get current ends
        vector<int> ends;
        map<int, pair<int, int>> end_info; // end -> (chain_idx, 0:front 1:back)
        for (int ci = 0; ci < chains.size(); ++ci) {
            int fr = chains[ci].front();
            int bk = chains[ci].back();
            if (find(ends.begin(), ends.end(), fr) == ends.end()) {
                ends.push_back(fr);
                end_info[fr] = {ci, 0};
            }
            if (find(ends.begin(), ends.end(), bk) == ends.end()) {
                ends.push_back(bk);
                end_info[bk] = {ci, 1};
            }
        }
        // now ind check and resolve
        vector<int> current_f = ends;
        bool ind_ok = false;
        while (!ind_ok && !current_f.empty()) {
            vector<int> order = current_f;
            random_shuffle(order.begin(), order.end());
            cout << order.size();
            for (int x : order) cout << " " << x;
            cout << "\n";
            cout.flush();
            vector<int> res_ind(order.size());
            for (int &x : res_ind) cin >> x;
            int hit_pos = -1;
            for (int j = 0; j < res_ind.size(); ++j) {
                if (res_ind[j]) {
                    hit_pos = j;
                    break;
                }
            }
            if (hit_pos == -1) {
                ind_ok = true;
                current_f = order; // ordered
                break;
            }
            // resolve
            int conf = order[hit_pos];
            vector<int> prev_order(order.begin(), order.begin() + hit_pos);
            // batch test conf vs prev_order
            vector<int> seq_m;
            seq_m.push_back(conf);
            for (int p : prev_order) {
                seq_m.push_back(p);
                seq_m.push_back(p);
            }
            seq_m.push_back(conf);
            cout << seq_m.size();
            for (int x : seq_m) cout << " " << x;
            cout << "\n";
            cout.flush();
            vector<int> res_m(seq_m.size());
            for (int &x : res_m) cin >> x;
            // parse
            vector<bool> adjs(prev_order.size(), false);
            int base = 1; // after conf on index 0
            for (int ii = 0; ii < prev_order.size(); ++ii) {
                int fb_idx = base + 2 * ii;
                adjs[ii] = res_m[fb_idx];
            }
            // find the one true
            int target_ii = -1;
            int cnt = 0;
            for (int ii = 0; ii < adjs.size(); ++ii) {
                if (adjs[ii]) {
                    target_ii = ii;
                    ++cnt;
                }
            }
            assert(cnt == 1);
            int target = prev_order[target_ii];
            // now merge chains of conf and target
            auto [c1, s1] = end_info[conf];
            auto [c2, s2] = end_info[target];
            if (c1 == c2) {
                // self loop, impossible
                assert(false);
            }
            // merge c1 and c2 connecting s1 of c1 to s2 of c2 via direct edge
            // orient
            deque<int> ch1 = chains[c1];
            if (s1 == 0) reverse(ch1.begin(), ch1.end());
            deque<int> ch2 = chains[c2];
            if (s2 == 1) reverse(ch2.begin(), ch2.end());
            // now back of ch1 to front of ch2
            for (int x : ch2) ch1.push_back(x);
            chains[c1] = ch1;
            // remove c2
            chains.erase(chains.begin() + c2);
            // now update current_f remove conf and target
            vector<int> new_f;
            for (int ee : current_f) {
                if (ee != conf && ee != target) new_f.push_back(ee);
            }
            current_f = new_f;
            // update end_info not needed since redo
        }
        if (current_f.empty()) {
            // all merged, done?
            break;
        }
        // now extension with current_f ind
        // light current_f random order
        vector<int> light_seq = current_f;
        random_shuffle(light_seq.begin(), light_seq.end());
        // now remain list
        vector<int> remain_l;
        for (int i = 1; i <= n; ++i) {
            if (known_set.find(i) == known_set.end()) remain_l.push_back(i);
        }
        int rsz = remain_l.size();
        // seq
        vector<int> seq = light_seq;
        for (int u : remain_l) {
            seq.push_back(u);
            seq.push_back(u);
        }
        // off light_seq
        for (int f : light_seq) seq.push_back(f);
        cout << seq.size();
        for (int x : seq) cout << " " << x;
        cout << "\n";
        cout.flush();
        vector<int> res(seq.size());
        for (int &x : res) cin >> x;
        // now parse the b for each remain
        vector<int> hit_u;
        int light_sz = light_seq.size();
        for (int ri = 0; ri < rsz; ++ri) {
            int pos_after_on = light_sz + 2 * ri;
            if (res[pos_after_on]) hit_u.push_back(remain_l[ri]);
        }
        // now for each hit_u, match to which in current_f
        int fsz = current_f.size();
        if (!hit_u.empty()) {
            vector<int> match_seq;
            for (int uu : hit_u) {
                match_seq.push_back(uu);
                vector<int> f_order = current_f;
                random_shuffle(f_order.begin(), f_order.end());
                for (int ff : f_order) {
                    match_seq.push_back(ff);
                    match_seq.push_back(ff);
                }
                match_seq.push_back(uu);
            }
            cout << match_seq.size();
            for (int x : match_seq) cout << " " << x;
            cout << "\n";
            cout.flush();
            vector<int> res_match(match_seq.size());
            for (int &x : res_match) cin >> x;
            // now parse for each hit_u
            int mbase = 0;
            for (int hi = 0; hi < hit_u.size(); ++hi) {
                int usize = 1 + 2 * fsz + 1;
                int uu = hit_u[hi];
                // find which f
                vector<int> connected_f;
                int base_pos = mbase + 1; // after uu on
                for (int fi = 0; fi < fsz; ++fi) {
                    int fb_pos = base_pos + 2 * fi;
                    if (res_match[fb_pos]) connected_f.push_back(current_f[fi]);
                }
                mbase += usize;
                // now connected_f size 1 or 2
                assert(connected_f.size() >= 1 && connected_f.size() <= 2);
                for (int cf : connected_f) {
                    // attach uu to cf 's chain
                    auto [ci, si] = end_info[cf]; // need end_info for current_f
                    // wait, end_info is for ends, but current_f is subset if resolved
                    // this is getting tricky, perhaps I need to update end_info after resolve
                    // to simplify, since small, for each connected_f, find which chain and side by checking if front or back of some chain
                    int target_ci = -1;
                    int target_si = -1;
                    for (int cii = 0; cii < chains.size(); ++cii) {
                        if (chains[cii].front() == cf) {
                            target_ci = cii;
                            target_si = 0;
                            break;
                        }
                        if (chains[cii].back() == cf) {
                            target_ci = cii;
                            target_si = 1;
                            break;
                        }
                    }
                    assert(target_ci != -1);
                    // now attach uu to that side
                    if (target_si == 0) {
                        chains[target_ci].push_front(uu);
                    } else {
                        chains[target_ci].push_back(uu);
                    }
                    known_set.insert(uu);
                    // add edge
                    // assume adj vector<vector<int>> adj(n+1);
                    adj[uu].push_back(cf);
                    adj[cf].push_back(uu);
                }
                if (connected_f.size() == 2) {
                    // merge the two chains
                    int ci1 = -1, si1 = -1, ci2 = -1, si2 = -1;
                    // find for first connected_f
                    for (int cii = 0; cii < chains.size(); ++cii) {
                        if (chains[cii].front() == connected_f[0]) {
                            ci1 = cii;
                            si1 = 0;
                            break;
                        }
                        if (chains[cii].back() == connected_f[0]) {
                            ci1 = cii;
                            si1 = 1;
                            break;
                        }
                    }
                    // similar for second
                    for (int cii = 0; cii < chains.size(); ++cii) {
                        if (cii == ci1) continue;
                        if (chains[cii].front() == connected_f[1]) {
                            ci2 = cii;
                            si2 = 0;
                            break;
                        }
                        if (chains[cii].back() == connected_f[1]) {
                            ci2 = cii;
                            si2 = 1;
                            break;
                        }
                    }
                    assert(ci1 != -1 && ci2 != -1);
                    // now merge ci1 and ci2 with u in between
                    // orient so back of ci1 to u to front of ci2
                    deque<int> ch1 = chains[ci1];
                    if (si1 == 0) reverse(ch1.begin(), ch1.end());
                    deque<int> ch2 = chains[ci2];
                    if (si2 == 1) reverse(ch2.begin(), ch2.end());
                    // now append u to ch1 back
                    ch1.push_back(uu);
                    // add edges uu to connected_f[0] and [1], already done
                    // then append ch2 to ch1
                    for (int x : ch2) ch1.push_back(x);
                    // now set chains[ci1] = ch1
                    chains[ci1] = ch1;
                    // remove ci2
                    chains.erase(chains.begin() + ci2);
                }
            }
        }
    }
    // now all known, now final connection
    vector<vector<int>> adj(n + 1);
    // add all known edges from chains
    for (auto &ch : chains) {
        for (int ii = 0; ii + 1 < ch.size(); ++ii) {
            int a = ch[ii], b = ch[ii + 1];
            adj[a].push_back(b);
            adj[b].push_back(a);
        }
    }
    // now collect final ends
    set<int> final_end_set;
    for (auto &ch : chains) {
        if (!ch.empty()) {
            final_end_set.insert(ch.front());
            final_end_set.insert(ch.back());
        }
    }
    vector<int> final_ends(final_end_set.begin(), final_end_set.end());
    int fends = final_ends.size();
    if (fends > 0) {
        // test all pairs
        vector<pair<int, int>> possible_pairs;
        for (int i = 0; i < fends; ++i) {
            for (int j = i + 1; j < fends; ++j) {
                possible_pairs.emplace_back(final_ends[i], final_ends[j]);
            }
        }
        int np = possible_pairs.size();
        vector<int> final_seq;
        for (auto [a, b] : possible_pairs) {
            final_seq.push_back(a);
            final_seq.push_back(b);
            final_seq.push_back(a);
            final_seq.push_back(b);
        }
        cout << final_seq.size();
        for (int x : final_seq) cout << " " << x;
        cout << "\n";
        cout.flush();
        vector<int> res_final(final_seq.size());
        for (int &x : res_final) cin >> x;
        // parse
        for (int pi = 0; pi < np; ++pi) {
            int base = 4 * pi;
            int b_pos = base + 1; // after first a 0, after b = base+1
            if (res_final[b_pos]) {
                int a = possible_pairs[pi].first, b = possible_pairs[pi].second;
                adj[a].push_back(b);
                adj[b].push_back(a);
            }
        }
    }
    // now build the perm from 1
    vector<int> perm;
    int start = 1;
    int curr = start;
    int pre = -1;
    set<int> visited;
    perm.push_back(curr);
    visited.insert(curr);
    while (true) {
        int nxt = -1;
        for (int nb : adj[curr]) {
            if (nb != pre) {
                nxt = nb;
                break;
            }
        }
        if (nxt == -1 || visited.count(nxt)) break;
        pre = curr;
        curr = nxt;
        perm.push_back(curr);
        visited.insert(curr);
        if (curr == start) break;
    }
    // if not full, try other direction
    if (perm.size() < n) {
        perm.clear();
        visited.clear();
        curr = start;
        pre = -1;
        perm.push_back(curr);
        visited.insert(curr);
        // choose the other neighbor
        int other_n = -1;
        for (int nb : adj[start]) {
            if (nb != adj[start][0]) { // arbitrary first
                other_n = nb;
                break;
            }
        }
        pre = adj[start][0]; // the first direction
        curr = other_n;
        perm.push_back(curr);
        visited.insert(curr);
        while (true) {
            int nxt = -1;
            for (int nb : adj[curr]) {
                if (nb != pre) {
                    nxt = nb;
                    break;
                }
            }
            if (nxt == -1 || visited.count(nxt)) break;
            pre = curr;
            curr = nxt;
            perm.push_back(curr);
            visited.insert(curr);
            if (curr == start) break;
        }
    }
    // now perm should have n
    assert(perm.size() == n);
    // output
    cout << -1;
    for (int p : perm) cout << " " << p;
    cout << "\n";
    cout.flush();
    return 0;
}