题解 矿物

传送门
官方题解

貌似人均能想到 \(O(nlogn)\) 就我一个只会个复杂度严格大于根号的破做法属实自闭

尝试找到一个 log 级别的做法
发现如果能维护出两个集合,使同一种矿物不在一个集合中,向下递归这个过程就能做到 log
然后调参照着题解调
最后我 Wrong Answer 90 了半天照着题解把 int len=ceil(p*s1.size()); 改成 int len=max(1, (int)(p*s1.size()-1)); 就过了
我也不知道这参咋调

点击查看代码
#include <vector>
#include <cmath>
#include <cassert>
#include <iostream>
#include "minerals.h"
using namespace std;
#define ll long long
#define pb push_back

int now, lst;
const double p=(3-sqrt(5))/2;
// const double p=0.362;
vector<int> s1, s2;
int inset[100010];

void solve(vector<int>& s1, vector<int>& s2, bool sit) {
	// cout<<"solve"<<endl;
	// cout<<"s1: "; for (auto it:s1) cout<<it<<' '; cout<<endl;
	// cout<<"s2: "; for (auto it:s2) cout<<it<<' '; cout<<endl;
	assert(s1.size()==s2.size());
	if (!s1.size()) return ;
	if (s1.size()==1) {
		Answer(s1[0], s2[0]);
		return ;
	}
	// int len=ceil(p*s1.size());
	int len=max(1, (int)(p*s1.size()-1));
	assert(len!=s1.size());
	vector<int> t1, t2, s3;
	for (int i=1,t; i<=len; ++i) {
		t=s1.back();
		now=Query(t), inset[t]^=1;
		t1.pb(t);
		s1.pop_back();
	}
	// for (auto& it:s1) if (!inset[it]) now=Query(it), inset[it]^=1;
	for (auto& it:s2) {
		if (t2.size()!=len) {
			lst=now; now=Query(it); inset[it]^=1;
			if ((sit==1&&lst!=now)||(sit==0&&lst==now)) t2.pb(it);
			else s3.pb(it);
		}
		else s3.pb(it);
	}
	solve(t1, t2, sit^1);
	solve(s1, s3, sit);
}

void Solve(int n) {
	for (int i=1; i<=2*n; ++i) {
		lst=now; now=Query(i);
		if (lst!=now) s1.pb(i);
		else s2.pb(i);
		inset[i]^=1;
	}
	solve(s1, s2, 1);
}
posted @ 2022-01-14 16:20  Administrator-09  阅读(0)  评论(0编辑  收藏  举报