1 条题解

  • 0
    @ 2025-8-24 23:01:25

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Petit_Souris
    鼓励的话语 无论多少次我都会说给你听 | 你在名为弱小的深渊 究竟看见过什么 | 天空中出现了一种罕见的天文现象

    搬运于2025-08-24 23:01:25,当前版本为作者最后更新于2024-07-31 15:34:37,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    我们考虑用 dp 算出期望最优的策略:设 fi,jf_{i,j} 表示剩下 ii 个人,其中有 jj 个人,他们中已经被确定至少有一个 11 的期望次数。

    j=0j=0 时,我们枚举 kk 表示查询 ii 个人中的多少人。如果这些人中没有 11(概率为 (1P)k(1-P)^k),会从 fik,0f_{i-k,0} 转移过来,否则会从 fi,kf_{i,k} 转移过来。

    j=1j=1 时,从 fi1,0f_{i-1,0} 转移过来(已经确定是这个人了)。

    j>1j>1 时,我们枚举 kk 表示查询这 jj 个人中的多少人。如果这些人中没有 11(概率为 (1P)k(1P)j1(1P)j\frac{(1-P)^{k}-(1-P)^{j}}{1-(1-P)^j}),会从 fik,jkf_{i-k,j-k} 转移过来,否则会从 fi,kf_{i,k} 转移过来。dp 的过程中记录转移的路径。

    交互过程只需要根据 dp 得到的路径来构造就行了。时间复杂度为 O(n3)\mathcal O(n^3),注意实现常数。

    #include <bits/stdc++.h>
    using namespace std;
    #define rep(i,a,b) for(int i=(a);i<=(b);++i)
    #define per(i,a,b) for(int i=(a);i>=(b);--i)
    /// You may use:
    
    // The number of students
    int N;
    
    // The probability any given student is positive
    double P;
    
    // This function performs a test on a subset of samples.
    // Its argument is a vector of Booleans of length N,
    // where the i-th element is true if the i-th sample should be added to the mix.
    // It returns true if (and only if) at least one of the samples in the mix is positive.
    bool test_students(std::vector<bool> mask) {
        assert(mask.size() == (size_t)N);
    
        std::string mask_str(N, ' ');
        for (int i = 0; i < N; i++)
            mask_str[i] = mask[i] ? '1' : '0';
    
        printf("Q %s\n", mask_str.c_str());
        fflush(stdout);
    
        char answer;
        scanf(" %c", &answer);
        return answer == 'P';
    }
    
    /// You should implement:
    
    // This function will be called once for each test instance.
    // It should use test_students to determine which samples are positive.
    // It must return a vector of Booleans of length N,
    // where the i-th element is true if and only if the i-th sample is positive.
    
    typedef double ld;
    const ld INF=1e9;
    ld dp[1009][1009],pb[1009];
    int trans[1009][1009];
    mt19937 rnd(time(0));
    std::vector<bool> find_positive(bool typ) {
        std::vector<bool> answer(N);
        if(typ){
            rep(i,0,N-1){
                vector<bool>msk(N);
                msk[i]=1;
                if(test_students(msk))answer[i]=1;
            }
            return answer;
        }
        vector<int>ord(N);
        iota(ord.begin(),ord.end(),0);
        shuffle(ord.begin(),ord.end(),rnd);
        int i=N,j=0;
        while(i){
            if(j==1){
                answer[ord[i-1]]=1;
                i--,j=0;
                // if(i)shuffle(ord.begin(),ord.begin()+i-1,rnd);
                continue;
            }
            vector<bool>msk(N);
            int k=trans[i][j];
            per(p,i-1,i-k)msk[ord[p]]=1;
            bool res=test_students(msk);
            if(j){
                if(!res)i-=k,j-=k;
                else j=k;
            }
            else {
                if(!res)i-=k;
                else j=k;
            }
        }
        return answer;
    }
    int main() {
        int T;
        scanf("%d %lf %d", &N, &P, &T);
        if(T>1){
            pb[0]=1;
            rep(i,1,N)pb[i]=pb[i-1]*(1-P);
            rep(i,0,N+1){
                rep(j,0,N+1)dp[i][j]=INF;
            }
            rep(i,0,N+1)dp[0][i]=0;
            rep(i,1,N){
                dp[i][1]=dp[i-1][0];
                rep(j,2,i){
                    rep(k,1,j){
                        ld prob=(pb[k]-pb[j])/(1-pb[j]);
                        ld val=dp[i-k][j-k]*prob+dp[i][k]*(1-prob)+1;
                        if(val<dp[i][j])dp[i][j]=val,trans[i][j]=k;
                    }
                }
                rep(j,1,i){
                    ld val=dp[i-j][0]*pb[j]+dp[i][j]*(1-pb[j])+1;
                    if(val<dp[i][0])dp[i][0]=val,trans[i][0]=j;
                }
            }
        }
        // You may perform any extra initialization here.
    
        for (int i = 0; i < T; i++) {
            std::vector<bool> answer = find_positive(T==1);
            assert(answer.size() == (size_t)N);
            std::string answer_str(N, ' ');
            for (int j = 0; j < N; j++)
                answer_str[j] = answer[j] ? '1' : '0';
    
            printf("A %s\n", answer_str.c_str());
            fflush(stdout);
    
            char verdict;
            scanf(" %c", &verdict);
            if (verdict == 'W')
                exit(0);
        }
    
        return 0;
    }
    
    • 1

    信息

    ID
    10573
    时间
    10000ms
    内存
    1024MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者