题解 矿物
貌似人均能想到 \(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);
}