Submission #1294449

#TimeUsernameProblemLanguageResultExecution timeMemory
1294449m_bezrutchkaCounting Mushrooms (IOI20_mushrooms)C++20
92.62 / 100
4 ms440 KiB
// 92 points, q = 245
#include "mushrooms.h"
#include <bits/stdc++.h>
using namespace std;

// alguma informacao que ainda nao estamos usando?
//   - de que nossas queries do passo 2 tem todos os elementos conhecidos iguais
//   - entao, paridade determina o valor do primeiro desconhecido
//   - isso quer dizer que cada query do passo 2 contribui em 1
//     para os sets do passo 1

// entao vamos usar:
// - passo 1: k queries para encontrar k iguais, como antes
// - passo 2: vamos sempre usando o maior set e atualizando os sets
//		total de caras novos descobertos a cada passo vai aumentando
//    k, k+1, k+1, k+2, k+2, ..., s, s
//    se no final o tamanho do set é s, eu tenho
//
//    total de posicoes contadas:
//     (2k - 1) + 2k + 2(k+1) + 2*(k+2) + ... + 2s
//    
//    quero
//    (2k - 1) + 2k + 2(k+1) + 2*(k+2) + ... + 2s >= n
//    1 + 2*((k-1) + k + k+1 + ... + s) >= n
//    2 * soma(k-1, s) >= n
//    s * (s + 1) - (k - 2) * (k - 1) >= n
//    arredonda pra
//    s^2 - (k - 1)^2 >= n
//    
//    (s - k) * (s + k) >= n
//    
//    numero de queries: k + 2 * (s - k) - 1 = 2s + k - 1
//    queremos 2s + k - 1 <= 226
//    s precisa ser > 100
//    vamos chutar s = 105:
//      posso fazer k = 33
//    fica 210 + 33 - 1 = 245 queries
//    
//    parece que nao da pra melhorar muito de 245
//    
//    acho que errei essa conta, to precisando colocar k maior pra dar mais ponto

int count_mushrooms(int n) {
	if (n == 1) return 1;

	vector<int> pos_A;
	vector<int> pos_B;

	pos_A.push_back(0);

	if (use_machine({0, 1}) == 0) pos_A.push_back(1);
	else pos_B.push_back(1);

	if (n == 2) return ((int) pos_A.size());

	if (use_machine({0, 2}) == 0) pos_A.push_back(2);
	else pos_B.push_back(2);

	int k = 70;

	// passo 1
	for (int i = 3; i < 2 * k - 1; i += 2) {
		if (i == n) return ((int) pos_A.size());
		if (i == n - 1) {
			return ((int) pos_A.size()) + (1 - use_machine({0, i}));
		}

		if ((int) pos_A.size() >= 2) {
			int ret = use_machine({i, pos_A[0], i+1, pos_A[1]});
			if (ret == 0) {
				pos_A.push_back(i);
				pos_A.push_back(i+1);
			} else if (ret == 1) {
				pos_B.push_back(i);
				pos_A.push_back(i+1);
			} else if (ret == 2) {
				pos_A.push_back(i);
				pos_B.push_back(i+1);
			} else {
				pos_B.push_back(i);
				pos_B.push_back(i+1);
			}
		} else {
			int ret = use_machine({i, pos_B[0], i+1, pos_B[1]});
			if (ret == 3) {
				pos_A.push_back(i);
				pos_A.push_back(i+1);
			} else if (ret == 2) {
				pos_B.push_back(i);
				pos_A.push_back(i+1);
			} else if (ret == 1) {
				pos_A.push_back(i);
				pos_B.push_back(i+1);
			} else {
				pos_B.push_back(i);
				pos_B.push_back(i+1);
			}
		}
	}

	int step = pos_A.size();
	bool using_b = false;
	if (pos_A.size() < pos_B.size()) {
		using_b = true;
		step = pos_B.size();
	}

	// cout << "pos_A: ";
	// for (int x: pos_A) {
	// 	cout << x << " ";
	// }
	// cout << endl;
	// cout << "pos_B: ";
	// for (int x: pos_B) {
	// 	cout << x << " ";
	// }
	// cout << endl;
	// cout << "using_b = " << using_b << endl;
	// cout << "step = " << step << endl;

	int ans = pos_A.size();
	int ini = 2 * k - 1;
	while (ini < n) {
		// ini x0 ini+1 x1 ini+2 x2 ... ini+step-1 xstep-1
		// alternadamente
		vector<int> aux;
		int last = min(n - 1, ini + step - 1);
		int cur_sz = last - ini + 1;
		for (int j = 0; j < cur_sz; j++) {
			aux.push_back({ini + j});
			int pos_to_use = using_b ? pos_B[j] : pos_A[j];
			aux.push_back(pos_to_use);
		}

		// cout << "will make query ";
		// for (int x: aux) {
		// 	cout << x << " ";
		// }
		// cout << endl;

		int ret = use_machine(aux);
		// cout << "got " << ret << endl;
		if (using_b) {
			ans += (ret + 1) / 2;
			if (ret % 2 == 0) {
				pos_B.push_back(ini);
			} else {
				pos_A.push_back(ini);
			}
		} else {
			ans += cur_sz - (ret + 1) / 2;
			if (ret % 2 == 0) {
				pos_A.push_back(ini);
			} else {
				pos_B.push_back(ini);
			}
		}
		ini += cur_sz;
		// cout << "now ans = " << ans << endl;
		// cout << "now ini = " << ini << endl;

		step = pos_A.size();
		using_b = false;
		if (pos_A.size() < pos_B.size()) {
			using_b = true;
			step = pos_B.size();
		}
	}

	return ans;
}
#Verdict Execution timeMemoryGrader output
Fetching results...