File size: 4,145 Bytes
14c9c2b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
#include <random>

using namespace std;

// Helper to interact with the judge
int query(const vector<int>& q) {
    cout << "0";
    for (int x : q) cout << " " << x;
    cout << endl;
    int res;
    cin >> res;
    return res;
}

// Helper to output the answer
void guess(const vector<int>& p) {
    cout << "1";
    for (int x : p) cout << " " << x;
    cout << endl;
    exit(0);
}

int main() {
    // Optimize I/O operations, though for interactive problems flushing is key
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int n;
    if (!(cin >> n)) return 0;

    if (n == 1) {
        guess({1});
        return 0;
    }

    vector<int> p(n + 1, 0);
    
    // We want to find one position with a known value to use as a pivot.
    // We look for pos[1] or pos[2].
    // Query strategy: q[i] = 1, others = 2.
    // If res == 2: p[i] == 1 (since pos[1]=i and pos[2]!=i).
    // If res == 0: p[i] == 2 (since pos[1]!=i and pos[2]=i).
    // If res == 1: neither (pos[1]!=i and pos[2]!=i).
    // We scan indices in random order to avoid worst-case inputs.
    vector<int> probe_order(n);
    iota(probe_order.begin(), probe_order.end(), 1);
    
    mt19937 rng(1337);
    shuffle(probe_order.begin(), probe_order.end(), rng);

    int base_idx = -1;
    int base_val = -1;

    // This loop takes at most N queries (guaranteed to find 0 or 2)
    for (int idx : probe_order) {
        vector<int> q(n);
        for (int i = 0; i < n; ++i) {
            if (i + 1 == idx) q[i] = 1;
            else q[i] = 2;
        }
        int res = query(q);
        if (res == 2) {
            base_idx = idx;
            base_val = 1;
            break;
        } else if (res == 0) {
            base_idx = idx;
            base_val = 2;
            break;
        }
    }

    // We record the found value
    p[base_idx] = base_val;
    
    // available indices for the remaining values
    vector<int> available;
    for (int i = 1; i <= n; ++i) {
        if (i != base_idx) available.push_back(i);
    }

    // values we still need to locate
    vector<int> to_find;
    for (int v = 1; v <= n; ++v) {
        if (v != base_val) to_find.push_back(v);
    }

    int found_count = 1; // currently we know 1 position

    // For each remaining value, binary search its position among available indices
    // This takes Sum(log2(k)) queries, which is ~ N log N but specifically log(N!) < 8600 for N=1000
    for (int val : to_find) {
        int l = 0;
        int r = available.size() - 1;
        
        while (l < r) {
            int mid = l + (r - l) / 2;
            
            // Construct query
            // Base: fill with base_val (known to be non-matching for unknown positions because base_val is unique at base_idx)
            // Known positions: fill with their correct values (contributes found_count matches)
            // Range [l, mid]: fill with target val (contributes +1 if pos[val] is here)
            
            vector<int> q(n);
            for(int i=1; i<=n; ++i) {
                if(p[i] != 0) {
                    q[i-1] = p[i];
                } else {
                    q[i-1] = base_val;
                }
            }
            
            // Overwrite probe range with candidate value
            for (int k = l; k <= mid; ++k) {
                int idx = available[k];
                q[idx-1] = val;
            }

            int res = query(q);
            
            // If val is in the probed range, we get one extra match
            if (res == found_count + 1) {
                r = mid;
            } else {
                l = mid + 1;
            }
        }
        
        // available[l] is the position of val
        int pos = available[l];
        p[pos] = val;
        found_count++;
        
        // Remove pos from available. erase is O(K), total loop is O(N^2) which is fine for N=1000
        available.erase(available.begin() + l);
    }

    // Output result
    vector<int> ans;
    for (int i = 1; i <= n; ++i) ans.push_back(p[i]);
    guess(ans);

    return 0;
}