Solution
這題是博主寫的第一道交互題,在此 mark 一下。
首先假設我們已經知道有若干蘑菇屬於 A(或者 B),這裏舉例 A 的情況。構造
可以查詢出序列中下劃線裏含有多少個 B,以及可以根據奇偶性知道 \(x\) 屬於 A 或者 B。
然後每次不斷擴大集合 A,B 的大小,精細求解極值可以得到操作次數 \(\sim 2\sqrt n\)。這樣做大概有 80 pts。
發現在某些時刻下,使用
查詢可以同時知道 \(x\),\(y\) 屬於 A 還是 B。在開始的時候使用這種查詢,到達一個界 \(Limit\),如果 \(\max\{|A|,|B|\}>Limit\) 時使用上一種查詢,兩者結合後操作次數 \(\sim \sqrt{3n}\),可以得到 92 pts。(gjd的四名選手的得分)
前期查詢相當於一次查詢換得兩個蘑菇的類型,求解極值的過程中發現如果提高效率(即一次查詢換得更多的蘑菇類型),操作次數可以下降。
我們可以採取這樣的方法使得 2 次查詢換取 5 個蘑菇的類型。首先查詢
根據奇偶性得到 \(z\) 的類型,剩餘的根據其是否爲 2 得到 \(x\ne y\) 或者 \(x=y\)。若爲後者就賺了,因爲有 1 換 3。否則再次查詢
同樣可以根據奇偶性得到 \(v\) 的類型。剩餘的由於有 \(x \ne y\) 知道 \(x\) 和 \(y\) 合計貢獻 0 或者 4,\(u\) 貢獻 0 或 2。據此分辨出 \(x\),\(y\),\(u\) 的類型。這樣 2 次操作得到 5 個蘑菇的類型。
期望下很優秀,但交互庫是自適應的,發現最壞剛好卡滿 226 次?精細調整 \(Limit\) 並且多次提交即可通過此題。
(題外話:開頭使用一次 use_machine
一個打亂的序列可以避免被交互庫自適應數據卡滿。不過此做法無需使用)
當然還有使用 203 步解決問題的方法,詳見 whzzt 的 codeforces blog。
#include "mushrooms.h"
#include <bits/stdc++.h>
#define pb push_back
using std::vector; using std::max; using std::min;
const int Limit = 116;
int ans = 0, now = 1;
vector<int> v[2], a;
int MaxSize() { return max(v[0].size(), v[1].size()); }
int count_mushrooms(int n) {
v[0].pb(0);
if (n > 1000) {
while (MaxSize() == 1)
v[use_machine(vector<int>{0, now})].push_back(now), now++;
while (MaxSize() == 2) {
int cur = v[0].size() < v[1].size(), tmp = use_machine(vector<int>{v[cur][0], now, v[cur][1], now+1});
v[cur ^ (tmp & 1)].pb(now + 1), v[cur ^ (tmp / 2)].pb(now); now += 2;
}
while (MaxSize() <= Limit) {
int cur = v[0].size() < v[1].size(), tmp = use_machine(vector<int>{v[cur][0], now, v[cur][1], now + 1, v[cur][2], now + 2});
v[cur ^ (tmp & 1)].pb(now + 2); tmp /= 2;
if (tmp % 2 == 0)
v[cur ^ (tmp / 2)].pb(now), v[cur ^ (tmp / 2)].pb(now + 1), now += 3;
else if (v[cur^1].size() < 2) {
tmp = use_machine(vector<int>{v[cur][0], now, v[cur][1], now + 3});
v[cur ^ (tmp & 1)].pb(now + 3); v[cur ^ (tmp / 2)].pb(now); v[cur ^ 1 ^ (tmp / 2)].pb(now + 1);
now += 4;
} else {
tmp = use_machine(vector<int>{v[cur^1][0], now, v[cur^1][1], v[cur][0], now + 1, v[cur][1], now + 3, v[cur][2], now + 4}) - 1;
v[cur ^ (tmp & 1)].pb(now + 4);
v[cur ^ (tmp / 2 & 1)].pb(now + 3);
v[cur ^ 1 ^ (tmp / 4 & 1)].pb(now);
v[cur ^ (tmp / 4 & 1)].pb(now + 1);
now += 5;
}
}
}
for (; now < n;) {
int cur = v[0].size() < v[1].size(), block = min((int)v[cur].size(), n - now);
a.clear(); a.pb(v[cur][0]);
for (int i = 0; i < block - 1; i++) a.pb(now + i), a.pb(v[cur][i + 1]);
a.pb(now + block - 1);
int tmp = use_machine(a);
v[cur ^ (tmp & 1)].pb(now + block - 1);
ans += cur ? tmp/2 : block - tmp/2 - 1;
now += block;
}
return ans + v[0].size();
}