由于题目是让我们统计个数,当我们确定了$k$个$p_{i}$都为0或1后,再用至多$lceil frac{n-k}{k} ceil$次询问和$2(n-k)$个"$n$"即可求出答案
具体构造就是将这$k$个数放在一排,并在中间插入未确定的$k$个数,中间$k-1$个数中不同于确定的$k$个数则会贡献2的答案,最后一个位置上的数根据答案奇偶性即可确定
(可以发现对于"$n$",$10^{5}$的限制是很宽松的,因此以下都不考虑对"$n$"的影响)
考虑如何找到这$k$个数:
有一个$2k-2$次的做法,每次询问$a={0,i}$,最坏产生了$k-2$次$p_{i}=0$和$k-1$次$p_{i}=1$,那么再下一次及一定可行
当我们已经知道两个$p_{i}$相同的位置时(设为$x$和$y$)询问$,a={x,i,y,j}$就可以求出$i$和$j$的类型(类似上面),最坏需要$2+(k-2)=k$次(恰好),算上$lceil frac{n-k}{k} ceil$最小值大约为282,在$137le kle 146$时取到(由于自适应性,这些最坏情况都是会被取到的)
继续扩大范围,询问$a={x,i,y,j,z,k}$,对答案分类讨论:
1.根据答案奇偶性,确定$k$,并令答案除以2;
2.若答案(除以2后)为0或2,则可以直接确定$i$和$j$;
3.否则(答案为1),我们无法得出$i$和$j$的状态,但可以利用$i$和$j$状态不同的条件
分类讨论,若已经确定的另一类型数量小于2,再加上一个未确定的数$l$,询问$a={x,l,y,i,z,j}$,根据上述条件就可以直接确定$i,j,l$
否则,设另一类的两个分别为$x'$和$y'$,再加上两个未确定的数$l,t$,询问$a={x',i,y',x,j,y,l,z,t}$,对答案分类讨论:
1.先将答案-1,因为$y'$与$x$一定会产生1的答案;
2.根据答案奇偶性,确定$t$,并令答案除以2;
3.当$i$改变后,$j$也对应改变,因此$i$对答案的影响为2(除以2后),而$l$对答案的影响为1,即通过答案(除以2后)的奇偶性可以确定$l$,再判断答案是否大于等于2可以确定$i$
这样最坏需要$3+2lceilfrac{2k-5}{5} ceil$,算上$lceil frac{n-k}{k} ceil$最小值大约为254,在$k=154,159,160,164$时取到
细节优化:
1.在统计答案的过程中,我们可以确定最后一个位置上的数,不妨将其加入来增大$k$;
2.可以适当的调整$k$的值(我选的$k=100$只有96,选$k=110$就过了)
3.当$n<2k+3$,为了避免一些特判,可以直接做$o(n)$的暴力
1 #include "mushrooms.h" 2 #include<bits/stdc++.h> 3 using namespace std; 4 #define K 110 5 queue<int>q; 6 vector<int>a,v[2]; 7 int get(){ 8 int k=q.front(); 9 q.pop(); 10 return k; 11 } 12 void calc1(){ 13 a.clear(); 14 a.push_back(0); 15 a.push_back(get()); 16 v[use_machine(a)].push_back(a[1]); 17 } 18 void calc2(){ 19 int p=(v[0].size()<2); 20 a.clear(); 21 a.push_back(v[p][0]); 22 a.push_back(get()); 23 a.push_back(v[p][1]); 24 a.push_back(get()); 25 int s=use_machine(a); 26 v[(s/2)^p].push_back(a[1]); 27 v[(s%2)^p].push_back(a[3]); 28 } 29 void calc3(){ 30 int p=(v[0].size()<3); 31 a.clear(); 32 a.push_back(v[p][0]); 33 a.push_back(get()); 34 a.push_back(v[p][1]); 35 a.push_back(get()); 36 a.push_back(v[p][2]); 37 a.push_back(get()); 38 int s=use_machine(a); 39 v[(s%2)^p].push_back(a[5]); 40 s/=2; 41 if ((s==0)||(s==2)){ 42 v[(s/2)^p].push_back(a[1]); 43 v[(s/2)^p].push_back(a[3]); 44 } 45 else{ 46 if (v[p^1].size()<2){ 47 a[5]=a[3]; 48 a[3]=a[1]; 49 a[1]=get(); 50 int s=use_machine(a); 51 v[(s&1)^p].push_back(a[5]); 52 v[(s&1)^p^1].push_back(a[3]); 53 if ((s&1)==0)s-=2; 54 v[(s/2)^p].push_back(a[1]); 55 } 56 else{ 57 a[0]=v[p^1][0]; 58 a[2]=v[p^1][1]; 59 a[4]=a[3]; 60 a[3]=v[p][0]; 61 a[5]=v[p][1]; 62 a.push_back(get()); 63 a.push_back(v[p][2]); 64 a.push_back(get()); 65 int s=use_machine(a)-1; 66 v[(s&1)^p].push_back(a[8]); 67 s/=2; 68 v[(s&1)^p].push_back(a[6]); 69 v[(s/2)^p].push_back(a[4]); 70 v[(s/2)^p^1].push_back(a[1]); 71 } 72 } 73 } 74 int calc4(){ 75 int p=(v[0].size()<v[1].size()); 76 a.clear(); 77 for(int i=0;(i<v[p].size())&&(!q.empty());i++){ 78 a.push_back(v[p][i]); 79 a.push_back(get()); 80 } 81 int s=use_machine(a); 82 v[(s&1)^p].push_back(a[a.size()-1]); 83 if (p)return s/2; 84 return a.size()/2-s/2-1; 85 } 86 int count_mushrooms(int n){ 87 v[0].push_back(0); 88 for(int i=1;i<n;i++)q.push(i); 89 if (n<2*K+3){ 90 while (!q.empty())calc1(); 91 return v[0].size(); 92 } 93 while (max(v[0].size(),v[1].size())<2)calc1(); 94 while (max(v[0].size(),v[1].size())<3)calc2(); 95 while (max(v[0].size(),v[1].size())<K)calc3(); 96 int ans=0; 97 while (!q.empty())ans+=calc4(); 98 return ans+v[0].size(); 99 }