[IOI2020]數蘑菇

Solution

這題是博主寫的第一道交互題,在此 mark 一下。

首先假設我們已經知道有若干蘑菇屬於 A(或者 B),這裏舉例 A 的情況。構造

\[A,\_,A,\_,\cdots,\_,A,x \]

可以查詢出序列中下劃線裏含有多少個 B,以及可以根據奇偶性知道 \(x\) 屬於 A 或者 B。

然後每次不斷擴大集合 A,B 的大小,精細求解極值可以得到操作次數 \(\sim 2\sqrt n\)。這樣做大概有 80 pts。

發現在某些時刻下,使用

\[A,x,A,y \]

查詢可以同時知道 \(x\)\(y\) 屬於 A 還是 B。在開始的時候使用這種查詢,到達一個界 \(Limit\),如果 \(\max\{|A|,|B|\}>Limit\) 時使用上一種查詢,兩者結合後操作次數 \(\sim \sqrt{3n}\),可以得到 92 pts。(gjd的四名選手的得分)

前期查詢相當於一次查詢換得兩個蘑菇的類型,求解極值的過程中發現如果提高效率(即一次查詢換得更多的蘑菇類型),操作次數可以下降。

我們可以採取這樣的方法使得 2 次查詢換取 5 個蘑菇的類型。首先查詢

\[A,x,A,y,A,z \]

根據奇偶性得到 \(z\) 的類型,剩餘的根據其是否爲 2 得到 \(x\ne y\) 或者 \(x=y\)。若爲後者就賺了,因爲有 1 換 3。否則再次查詢

\[B,x,B,A,y,A,u,A,v \]

同樣可以根據奇偶性得到 \(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();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章