Codeforces Round 865 (Div. 2) D. Sum Graph

121 阅读2分钟

D - Sum Graph

题目内容

This is an interactive problem. There is a hidden permutation p1,p2,,pnp_1, p_2, \dots, p_n. Consider an undirected graph with nn nodes only with no edges. You can make two types of queries: Specify an integer xx satisfying 2x2n2 \le x \le 2n. For all integers ii (1in1 \le i \le n) such that 1xin1 \le x-i \le n, an edge between node ii and node xix-i will be added. Query the number of edges in the shortest path between node pip_i and node pjp_j. As the answer to this question you will get the number of edges in the shortest path if such a path exists, or 1-1 if there is no such path. Note that you can make both types of queries in any order. Within 2n2n queries (including type 11 and type 22), guess two possible permutations, at least one of which is p1,p2,,pnp_1, p_2, \dots, p_n. You get accepted if at least one of the permutations is correct. You are allowed to guess the same permutation twice. A permutation of length nn is an array consisting of nn distinct integers from 11 to nn in arbitrary order. For example, [2,3,1,5,4][2,3,1,5,4] is a permutation, but [1,2,2][1,2,2] is not a permutation (22 appears twice in the array), and [1,3,4][1,3,4] is also not a permutation (n=3n=3 but there is 44 in the array).

中文大意

给我们n个点没有边的无向图 这时有操作一和操作二

  1. 输入一个整数 x 将 i 和 x - i连边并且 i和x - i都在[1, n] 的范围内
  2. 输入两个整数i, j若存在路径返回i->j的最短路否则返回-1
    让我们在2n次操作内去猜测可能的序列

解法

当我们进行两次x 为n,n+1的操作一我们会发现这个图被连成了一条直线并且端点是n和(n + 1) / 2所有我们可以通过n - 1次查询去求得端点然后再通过n-1次查询去确定位置,最后输出即可

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define int long long
// #define endl '\n'
#define pb push_back
#define NO cout << "NO" << endl;
#define YES cout << "YES" << endl;
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=n;i>=a;i--)
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<VI> VII;
ll MOD;
ll powmod(ll a,ll b) {ll res=1;a%=MOD; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%MOD;a=a*a%MOD;}return res;}
mt19937 mrand(random_device{}()); 
const int N = 2e5 + 10;
/*
    3 2 6 1 4 5 2次
    1 2 
*/
void solve()
{
    int n; cin >> n;
    VII e(n + 1);
    int k = n;
    for (int i = 1; i <= n; i++) {
        if (i == k) {
            k--;
            continue;
        }
        e[i].pb(k--);
    }
    k = n - 1;
    for (int i = 1; i < n; i++) {
        if (i == k) {
            k--;
            continue;
        }
        e[i].pb(k--);
    }
    VI a(n + 1);
    function<void(int, int, int)> dfs = [&] (int u, int fa, int num) {
        a[num] = u;
        // cout << num << endl;
        for (auto v : e[u]) if (v != fa) {
            dfs(v, u, num + 1);
        }
    };
    cout << "+ " << n + 1 << endl;
    int x; cin >> x;
    if (x == -2) return;
    cout << "+ " << n << endl;
    cin >> x;
    if (x == -2) return;
    dfs(n, 0, 1);
    // rep (i, 1, n) cout << a[i] << " \n"[i==n];
    int mx = 0, d = 0;
    for (int i = 2; i <= n; i++) {
        cout << "? 1" << ' ' << i << endl;
        cin >> x;
        if (x == -2) return;
        if (x > mx) {
            mx = x;
            d = i;
        }
    }
    VI res(n + 1), ans(n + 1);
    rep (i, 1, n) {
        if (i == d) continue;
        cout << "? " << d << ' ' << i << endl;
        cin >> x;
        if (x == -2) return;
        res[i] = a[x + 1];
        // cout << i << " res=" << a[x + 1] << endl; 
        ans[i] = a[n - x];
        // cout << i << " ans=" << a[n - x] << endl;
    }
    res[d] = a[1], ans[d] = a[n];
    cout << "! ";
    rep (i, 1, n) cout << res[i] << ' ';
    rep (i, 1, n) cout << ans[i] << ' ';
    cout << endl;
    cin >> x;
    if (x == -2) return;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int T;cin >> T;
    while ( T -- )
    solve();
    return 0;
}