zoukankan      html  css  js  c++  java
  • 【UOJ568】【IOI2020】Mushrooms(交互)

    题目链接

    • (n) 个蘑菇(标号为 (0sim n-1)),分为 A,B 两类,已知 (0) 号蘑菇属于 A 类。
    • 你可以进行 (Q) 次询问操作,每次挑选出若干蘑菇,以任意顺序排成一排,交互器会告诉你有多少对相邻蘑菇是不同类的。
    • 要求求出有多少个蘑菇属于 A 类。
    • (1le nle2 imes10^4)(Q=226)

    大批的询问方式

    容易发现根据 A+(i_1)+A+(i_2)+(cdots)+A+(i_{k})(其中的 A 可以全部替换为 B)的形式,可以得知这 (k) 个蘑菇中共有多少个 A 类蘑菇。同时,由于只有标号为 (i_k) 的蘑菇的贡献是 (0/1),其余都是 (0/2),我们还可以确定出 (i_k) 这一个蘑菇的种类。

    当已知大批蘑菇的种类时,这应该算是一种比较优的询问方式了。但如果全部用这样搞,由于起步过慢,并不能在限定次数内求出答案。

    所以,我们需要在一开始先快速求出一些蘑菇的种类,然后再按照上面的方式去做。

    初始的询问方式

    如果每种最多只知道一个蘑菇,那么也只能用 A+(x) 询问,来求出 (x) 的种类。

    当某一种有两个蘑菇了,容易想到每次询问 A+(x)+A+(y),一次询问可以求出两个蘑菇的种类。然而这样并不优秀。

    考虑我们每次直接询问 A+(x)+A+(y)+A+(z),那么 (z) 的种类可以直接确定,如果 (x)(y) 的种类相同也可以直接确定它们。

    关键问题就在于 (x,y) 种类不同,此时我们可以再带着它们询问一次 A+(x)+A+(u)+A+B+(y)+B+(v)。(如果 B 的个数此时还不到两个,我们可以用 A+(x) 确定 (x) 的种类,也就确定了 (y) 的种类。因为 (x,y) 种类相反,最多出现两次这样的情况。) (x)(y) 种类相反所以贡献之和是 (0/4)(u) 的贡献是 (0/2)(v) 的贡献是 (0/1),减去已知的 AB 之间的一点固定贡献之后,就能一波推出 (x,y,u,v) 的种类。

    综上,最坏的情况是通过两次询问求出 (5) 个蘑菇的种类,平均一次询问可以求出 (2.5) 个。

    然后稍微调调阈值就过了。

    代码:(O(n))

    #include "mushrooms.h"
    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Tq template<typename... Ar>
    #define Ts template<typename Ty,typename... Ar>
    #define Rg register
    #define RI Rg int
    #define Cn const
    #define CI Cn int&
    #define I inline
    #define W while
    #define pb push_back
    #define eb pop_back
    using namespace std;
    vector<int> S,P[2];
    Tp I int Q(Ty x) {return S.pb(x),use_machine(S);}
    Ts I int Q(Ty x,Ar... y) {return S.pb(x),Q(y...);}
    Tq I int G(Ar... y) {return S.clear(),Q(y...);}
    int count_mushrooms(int n)
    {
    	RI c=1;P[0].pb(0);W(c^n&&(int)max(P[0].size(),P[1].size())<2) P[G(0,c)].pb(c),++c;//每种最多只知道一个蘑菇:A+x
    	RI o,op=P[1].size()==2;W(c+1<n&&(int)max(P[0].size(),P[1].size())<3) o=G(P[op][0],c,P[op][1],c+1),P[(o>>1)^op].pb(c++),P[(o&1)^op].pb(c++);//每种最多只有两个蘑菇:A+x+A+y
    	RI i;for(i=1;c<=199&&c+2<n;++i,c+=3)//设个阈值,先快速求出一些蘑菇的种类
    	{
    		op=P[0].size()<P[1].size(),o=G(P[op][0],c,P[op][1],c+1,P[op][2],c+2),P[(o&1)^op].pb(c+2);//A+x+A+y+A+z,确定z
    		if(!(o&2)) {P[(o>>2)^op].pb(c),P[(o>>2)^op].pb(c+1);continue;}//如果x,y相同可以直接确定
    		if(P[op^1].size()<2||c+4>=n) {P[o=G(0,c)].pb(c),P[o^1].pb(c+1);continue;}//如果另一种蘑菇少于2个直接A+x
    		o=G(P[op][0],c,P[op][1],c+3,P[op][2],P[op^1][0],c+1,P[op^1][1],c+4)-1,//A+x+A+u+A+B+y+B+v
    		P[(o&1)^op^1].pb(c+4),P[(o>>1&1)^op].pb(c+3),P[(o>>2)^op].pb(c),P[(o>>2)^op^1].pb(c+1),c+=2;//一波推出x,y,u,v
    	}
    	RI k,t=P[0].size();W(c^n)//大批的询问方式
    	{
    		for(k=P[op=P[0].size()<P[1].size()].size(),S.clear(),i=0;i^k&&c^n;++i) S.pb(P[op][i]),S.pb(c++);//A+i1+A+i2+...+A+ik
    		o=use_machine(S),op?t+=o+1>>1:t+=i-(o+1>>1),P[(o&1)^op].pb(c-1);//更新答案,同时求出ik的种类
    	}return t;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    JAVA 面向对象的扩展 内部类
    对于win10 更换JDK后 查询JDK路径还是原路径的解决办法
    懂得的懂
    稀疏数组转化二维数组
    Flume的安装配置
    CentOS7配置ip和ssh免密登录和hadoop环境
    AOP的使用和事务
    spring的个人理解
    单车月结算2-修改和删除功能
    单车月结算1
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/UOJ568.html
Copyright © 2011-2022 走看看