Hướng dẫn giải của Bedao Grand Contest 11 - HIDDENPER


Chỉ dùng lời giải này khi không có ý tưởng, và đừng copy-paste code từ lời giải này. Hãy tôn trọng người ra đề và người viết lời giải.
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.

Tác giả: bedao

Subtask 1

Với mỗi ~1\le i<n~, ta hỏi hai hoán vị ~P~ và ~Q~ sao cho ~P_0=1,P_i=N~ và ~Q_0=N,Q_i=1~ đồng thời các vị trí còn lại bằng nhau. Ta nhận được hai tổng ~X_0-X_i+C~ và ~X_i-X_0+C~, từ đây ta tính được hiệu ~X_i-X_0~. Để ý rằng khi ~X_i=1~ thì hiệu này đạt giá trị nhỏ nhất, ta tính được ~X_0~ và từ đó dễ dàng khôi phục được hoán vị.</p>

Subtask 2

Ở subtask 1 ta chỉ mới sử dụng giá trị ~1~ và ~N~, để giảm số câu hỏi ta sẽ sử dụng thêm giá trị ~2~. Và để phá được dấu giá trị tuyệt đối thì ta chỉ nên đặt ~2~ vào các vị trí mà ta đã biết nó lớn hơn ~1~.

Xét ba vị trí ~i, j, k~ với điều kiện ta đã biết ~X_i>1~. Ta hỏi hai hoán vị ~P~ và ~Q~ sao cho ~P_i=2,P_j=1,P_k=N~ và ~Q_i=2,Q_j=N,Q_k=1~. Ta nhận được hai tổng ~X_i+X_j-X_k+C~ và ~X_i-X_j+X_k+C~, tính hiệu ~X_j-X_i~ và xác định vị trí lớn hơn, giả sử đó là ~j~. Ta hỏi tiếp hoán vị ~R~ sao cho ~R_i=N,R_j=2,R_k=1~ và nhận được tổng ~-X_i+X_j+X_k+C~. Từ đây dễ dàng tìm được ~X_k-X_i~. Trường hợp ~k~ là chỉ số lớn hơn ta xử lý tương tự.

Trở lại với bài toán, đầu tiên ta tìm hiệu ~X_1-X_0~ và xác định vị trí chắc chắn lớn hơn ~1~. Sau đó cứ mỗi hai phần tử liên tiếp ta áp dụng thuật toán trên và thu được các hiệu, từ đó sử dụng nhận xét ở cuối subtask 1 để khôi phục hoán vị.

Code mẫu

#include <bits/stdc++.h>

using namespace std;

const int N = 505;

int a[N], b[N], p[N], n;

int ask() {
  cout << "ask";
  for (int i = 0; i < n; i++)
    cout << ' ' << p[i];
  cout << endl;
  int res = 0; cin >> res;
  // for (int i = 0; i < n; i++)
    // res += abs(b[i] - p[i]);
  return res;
}

void ask_two(int x, int y) {
  memset(p, 0, sizeof p);
  p[x] = 1; p[y] = n;
  for (int i = 0, j = 2; i < n; i++)
    if (!p[i]) p[i] = j++;
  int pre = ask();
  swap(p[x], p[y]);
  int nex = ask();
  a[y] = (nex - pre) / 2;
}

void ask_three(int x, int y, int z) {
  memset(p, 0, sizeof p);
  p[x] = 2; p[y] = 1; p[z] = n;
  for (int i = 0, j = 3; i < n; i++)
    if (!p[i]) p[i] = j++;
  int pre = ask();
  swap(p[y], p[z]);
  int nex = ask();
  a[y] = (nex - pre) / 2;
  if (a[y] > 0) {
    p[x] = n; p[y] = 1; p[z] = 2;
  } else {
    p[x] = n; p[y] = 2; p[z] = 1;
  }
  nex = ask();
  a[z] = (nex - pre) / 2;
  a[y] = a[z] - a[y];
}

void answer() {
  cout << "answer";
  for (int i = 0; i < n; i++)
    cout << ' ' << a[i];
  cout << endl;
}

int main() {
  int test, U; cin >> test;
  while (test--) {
    cin >> n >> U;
    // for (int i = 0; i < n; i++)
      // cin >> b[i];
    memset(a, 0, sizeof a);
    ask_two(0, 1);
    int t = 0;
    if (a[1] > 0) {
      a[0] = -a[1]; a[1] = 0; t = 1;
    }
    for (int i = 2; i < n; i += 2) {
      if (i == n - 1) ask_two(t, i);
      else ask_three(t, i, i + 1);
    }
    int mn = 0;
    for (int i = 0; i < n; i++)
      mn = min(mn, a[i]);
    for (int i = 0; i < n; i++)
      a[i] -= mn - 1;
    answer();
  }
}

Bình luận

Hãy đọc nội quy trước khi bình luận.


Không có bình luận tại thời điểm này.