题解:P6837 [IOI 2020] 数蘑菇

题目传送门

考虑如何通过查询来尽可能多地得到蘑菇地种类信息。


算法一

由于开始已知了一个 \(A\) 型蘑菇 \(0\)。查询 \(\{0,x\}\) 就可以得知 \(x\) 的类型。

这样需要 \(n-1\) 次,期望得分 \(10 pts\)


算法二

假设我们此时已知了 \(x\)\(A\) 型蘑菇,\(y\)\(B\) 型蘑菇,不妨设 \(x>y\)

如果我们询问 \(\{A_1 p_1 A_2 p_2 \dots A_x p_x\}\),记结果为 \(res\),我们就可以得到 \(p_{1\dots x}\) 中有 \(\lfloor\frac{res}{2}\rfloor\)\(B\) 型蘑菇,其余为 \(A\) 型蘑菇,一次查询直接解决了 \(x\) 个蘑菇。

同时,根据 \(res\) 的奇偶性,可以判断 \(p_x\) 的类型。那么,每次把新的 \(p_x\) 也加入 \(x\)\(y\) 中,使得增长速度加快。在交互库自适应的条件下,需要 \(280\) 次左右。

期望得分 \(80pts\)


算法三

算法三是对算法一的优化。

考虑查询 \(\{A_1 p A_2 q\}\)。除了通过奇偶性判断 \(q\) 以外,\(q\) 确定了也可以使得 \(p\) 确定。达到了一次确定两个的效果。

这样就需要 \(\frac{n-1}{2}\) 次,期望得分 \(25pts\)


算法四

算法四是对算法一的进一步优化。

考虑通过两次查询来确定五个蘑菇 \(p_{1\sim 5}\)

先查询 \(\{A_1p_1A_2p_2A_3p_3\}\),直接得到了 \(p_3\),同时如果 \(p_1\)\(p_2\) 种类相同的话,也可以得到。

先假设 \(p_1,p_2\) 种类不同。

考虑查询 \(\{A_1p_1A_2B_1p_2B_2p_4B_3p_5\}\)

首先通过奇偶性得到 \(p_5\),然后发现 \(p_1,p_2\) 的贡献为 \(0/4\)\(p_4\) 的贡献为 \(0/2\),可以直接分离出每个部分的贡献,分别分析出种类。

这样就需要 \(\frac{2(n-1)}{5}\) 次,期望得分还是 \(25pts\)

算法五

算法三和四的意义在于加速算法二的增长速度。算法二每两次只能增长 \(1\) 的速度,然而套用算法三和四就可以更快。

考虑使用算法三。

根据贪心可以得到,在一开始使用完算法三是较优的。即考虑先在 \(\max(x,y)\le m\) 时使用算法三。然后再使用算法二,通过调整参数 \(m\) 发现,最优在 \(m=80\sim 90\) 时,得分 \(92pts\)

考虑使用算法五。

\(m=100\) 时,期望得分 \(100pts\)


实现细节:

  1. \(\max(x,y)<2\) 时,只能用算法一,所以有必要实现算法一。

  2. \(\min(x,y)<3\) 是,不能用算法四,所以有必要实现算法二。在此情况下如果 \(\min(x,y)\) 一直达不到 \(3\),也就是一直发现数量多的一种,那么用算法二 \(\max(x,y)\) 会增长的很快,反而更优。

  3. 当使用算法二时,如果 \(\max(x,y)\) 已经大于剩余的未知蘑菇数量,不要改用算法一三四来做剩下的,使用算法二就可以一次解决。

#include <bits/stdc++.h>
using namespace std;
// inline int read(){
//     int d=0,f=0;char ch=getchar();
//     while (!isdigit(ch)) f|=(ch=='-'),ch=getchar();
//     while (isdigit(ch)) d=d*10+ch-'0',ch=getchar();
//     return f?-d:d;
// }
const int N=20005;
int n,sum,R,A[N],B[N],cA,cB,col[N],cnt,tot;
int use_machine(vector<int> x);
// {
//     int lst=-1,res=0;cnt++;
//     for (int i:x){
//         if (lst!=-1&&col[i]!=col[lst]) res++;
//         lst=i;tot++;
//     }
//     return res;
// }
inline void solve1(){//1 换 1 
    int res=use_machine({0,++R});
    if (res) B[++cB]=R;else A[++cA]=R;
}
inline void solve2(){//1 换 2
    if (cA>=2){
        int res=use_machine({A[1],R+1,A[2],R+2});
        if (res%2==0) A[++cA]=R+2;else B[++cB]=R+2,res--;
        if (!res) A[++cA]=R+1;else B[++cB]=R+1;
    }
    else {
        int res=use_machine({B[1],R+1,B[2],R+2});
        if (res%2==0) B[++cB]=R+2;else A[++cA]=R+2,res--;
        if (!res) B[++cB]=R+1;else A[++cA]=R+1;
    }
    R+=2;
}
inline void solve3(){//2 换 5
    int r1=use_machine({A[1],R+1,A[2],R+2,A[3],R+3});
    if (r1%2==0) A[++cA]=R+3;else B[++cB]=R+3,r1--;
    if (r1==0){A[++cA]=R+1,A[++cA]=R+2,R+=3;return ;}//见好就收
    if (r1==4){B[++cB]=R+1,B[++cB]=R+2,R+=3;return ;}
    int r2=use_machine({A[1],R+1,A[2],B[1],R+2,B[2],R+4,B[3],R+5})-1;//注意减一
    if (r2%2==0) B[++cB]=R+5;else A[++cA]=R+5;
    if (r2&2) A[++cA]=R+4;else B[++cB]=R+4;
    if (r2&4) B[++cB]=R+1,A[++cA]=R+2;
    else A[++cA]=R+1,B[++cB]=R+2;
    R+=5;
}
inline void solve4(){//1 换 n
    vector <int> V;
    if (cA>cB) {
        for (int i=1;i<=cA&&R<n-1;i++) V.push_back(A[i]),V.push_back(++R);
        int res=use_machine(V);sum+=V.size()/2-1-res/2;
        if (res&1) B[++cB]=R;else A[++cA]=R;
    }
    else {
        for (int i=1;i<=cB&&R<n-1;i++) V.push_back(B[i]),V.push_back(++R);
        int res=use_machine(V);sum+=res/2;
        if (res&1) A[++cA]=R;else B[++cB]=R;
    }
}
int count_mushrooms(int _n){
    n=_n,A[++cA]=0;
    while (max(cA,cB)<2&&R<n-1) solve1();//解锁1换2
    while (max(cA,cB)<=100){//解锁1换n
        if (R+5>=n) {
            while (R!=n-1) solve4();
            return sum+cA;
        } 
        if (min(cA,cB)<3) solve2();
        else solve3();
    }
    while (R!=n-1) solve4();
    return sum+cA;
}
// int main(){
//     freopen(".in","r",stdin);
//     freopen(".out","w",stdout);
//     int _n=read();
//     for (int i=0;i<_n;i++) col[i]=read();
//     int ans=count_mushrooms(_n);
//     printf("%d\n",ans);
//     if (cnt>226||tot>100000) 
//     printf("%d %d\n",cnt,tot);
//     // printf("ans:%d sum:%d cA:%d R:%d\n",ans,sum,cA,R);
// }

posted @ 2026-04-08 09:18  TP2010  阅读(8)  评论(0)    收藏  举报