[loj3368]数蘑菇

由于题目是让我们统计个数,当我们确定了$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 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/13825793.html