[ABC313] D - Odd or Even

[Q]https://atcoder.jp/contests/abc313/tasks/abc313_d
いてえ結果でした。80分あがいてWAでした。

考察
・K=1のとき
?1, ?2, …, ?Nで
で簡単に特定できると思う。

・とりあえずN通りの条件式を用意したい。
Q. K要素の連番を質問してみる。
?123
?234
?345…
とする場合はどうだろう?
A. ダメケースが存在する。

N=6, K=3の場合を考える。
? 1 2 3
?   2 3 4
?     3 4 5
?       4 5 6
? 1       5 6
? 1 2       6

これでわかる関係は、
(123) - (234) = 1-4の関係
(234) - (345) = 2-5の関係
(345) - (456) = 3-6の関係
(456) - (561) = 4-1の関係 <= すでに1つ目の調査で得られている。

つまり、NとKが互いに素でない場合に、閉路情報で無駄遣いしてしまうことになる。

NとKが互いに素な場合はACを得られる。
大半のケースで通るため、逆に厄介であった。この発想を捨てて転換しなきゃいけない。

Q. 解説を見る
次の2通りに分けるようだ。
1. まず、1~K+1までの要素を確定させる。質問はK+1回。総和を利用する。
2. 次に、K+2以降の値を個別に確定させる。

N=6, K=3の場合
1. まず1~4までの要素を個別に確定させる。

クエリは以下の4通りを聞く。
? 1 2 3
?   2 3 4
? 1   3 4
? 1 2   4

すると、それぞれの要素をK回ずつ利用しているのがわかる。
そのため、総和の偶奇は、
? 1 2 3 4 
と等しくなる。

これがわかるので、
(1234) - (123) = 4の情報
(1234) - (234) = 1の情報
(1234) - (134) = 2の情報
(1234) - (124) = 3の情報
を確定できた。

2. 次に、12の情報がわかっているので、
? 1 2 5
? 1 2   6
をしてしまえば、
(125) - (12) = 5の情報
(126) - (12) = 6の情報
が得られる。

実装

void query(vector<ll> &A) {
  cout << "? ";
  ll n = A.size();
  rep(i, n) { cout << (A[i] + 1) << " \n"[i == n - 1]; }
}
void answer(vector<ll> &A) {
  cout << "! ";
  ll n = A.size();
  rep(i, n) { cout << A[i] << " \n"[i == n - 1]; }
}

int main() {
  cincout();
 
  ll N, K;
  cin >> N >> K;
  vector<ll> ans(N);
  vector<ll> ret(N);
 
  // まず1~K+1までを確定。
  // そのあと、K+2~Nまでを確定。

  // まず?123 ?234 ?341 ?412で1234を確定
  ll sum = 0;
  rep(i, K + 1) {
    vector<ll> A(K);
    rep(j, K) { A[j] = (i + j) % (K + 1); }
    query(A);
    cin >> ret[i];
    sum ^= ret[i];
  }
  rep(i, K + 1) { ans[(K + i) % (K + 1)] = sum ^ ret[i]; }
  // 次に?12を取得
  ll base = 0;
  rep(i, K - 1) base ^= ans[i];
  // 最後に?125, ?126
  for (ll i = K + 1; i < N; ++i) {
    vector<ll> A(K);
    rep(j, K - 1) A[j] = j;
    A[K - 1] = i;
    query(A);
    cin >> ret[i];
    ans[i] = ret[i] ^ base;
  }
  answer(ans);
}


https://atcoder.jp/contests/abc313/submissions/44311804


この記事が気に入ったらサポートをしてみませんか?