• [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
  • 相关阅读:
    使用dataInput:DescriptionViewer对输入的数据进行校验
    Nunit2.6.2调试.net4类库
    使用WCF RIA服务支持ASP.NET验证
    偶遇 Lc.exe已退出代码为1
    android程序连接后端web service时,提示:Permission denied
    设置XP系统的自动登录
    DomainDataSource的自动刷新
    安装CentOS时,显示 NET:Registered protocol family 2
    清除SqlServer2008的日志
    http://www.cnblogs.com/KnightsWarrior/archive/2010/08/27/1809739.html(博客主)
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/13825793.html
Copyright © 2020-2023  润新知