zoukankan      html  css  js  c++  java
  • nowcoder 提高组模拟赛 选择题 解题报告

    选择题

    链接:

    https://www.nowcoder.com/acm/contest/178/B

    来源:牛客网

    题目描述

    有一道选择题,有 (a,b,c,d) 四个选项。

    现在有 (n) 个人来做这题,第 (i) 个人有 (p_{i,j}) 的概率选第 (j) 个选项。

    定义 (cnt(x)) 为选第 (x) 个选项的人数。

    (mx)(cnt(x)) 最大的 (x) (如果有多个(cnt(x))最大的 (x),则取其中 (x) 最小的),

    (cnt(mx) le lfloorfrac{n}{2} floor) ,则所有人得 (0) 分;

    否则令 (choice_i) 表示第 (i) 个人选的选项,则第 (i) 人得(w_{mx,choice_i})

    求每个人的期望得分。

    输入描述:

    第一行一个整数 (n) ,表示人数。

    接下来 (n) 行,每行 (4) 个整数,其中第 (i) 行第 (j) 个数表示 (p_{i,j}) ,即在模 (998244353) 意义下第 (i) 个人选第 (j) 个选项的概率。

    接下来 (4) 行,每行 (4) 个整数,第 (i) 行第 (j) 个数表示 (w_{i,j})

    输出描述:

    (n) 行,第 (i) 行表示第 (i) 个人在模 (998244353) 意义下的期望得分。

    备注:

    全部的输入数据满足:

    • (1 ≤ n ≤ 2000)
    • $0 ≤ p_{i,j} < 998244353 (1 ≤ i ≤ n,1 ≤ j ≤ 4) $
    • (sumlimits_{j=1}^4 p_{i,j} equiv 1 (mod 998244353)(1le i le n))

    各个测试点的性质如下

    测试点编号 n 特殊性质
    (1) (le 2)
    (2) (le 10) (p_{i,3}=p_{i,4}=0,(1le i le n))
    (3) (le 10)
    (4,5) (le 100) (p_{i,3}=p_{i,4}=0,(1le i le n))
    (6,7) (le 100) (p_{i,4}=0(1le i le n))
    (8,9,10,11) (le 100)
    (12sim20) (le 2000)

    Solution

    考试的时候打了55pts暴力,结果爆5了,原因竟然是出负数了没模正。。

    枚举每个人选什么和最后结果是什么,然后算一下其他人的选择对这个结果的概率。

    每次可以简单的(n^2)(dp)

    (dp_{i,j})代表前(i)个人有(j)个选了的和

    (dp_{i,j}=dp_{i-1,j-1}p_{i,k}+dp_{i-1,j}(1-p_{i,k}))

    发现每次只是少了一个人不进行(dp)

    可以先把所有人的(dp)搞出来,然后(O(n))把人踢出来

    具体的,设(dp_{i})(i)个人选了某选项的全集

    枚举每个人时,显然有(dp_i'=p_idp_{i-1}+(1-p_i)dp_i)

    那么回退时有(dp_i=frac{dp_i'-p_idp_{i-1}}{1-p_i})

    注意压维了的话是存在顺序的,还要特判(p_i=1)


    Code:

    #include <cstdio>
    #define ll long long
    const int N=2e3+10;
    const ll mod=998244353ll;
    int n;
    ll p[N][5],w[5][5],dp[N][5],inv[N][5],ans[N];
    ll quickpow(ll d,ll k)
    {
        ll f=1;
        d=(d%mod+mod)%mod;
        while(k)
        {
            if(k&1) f=f*d%mod;
            d=d*d%mod;
            k>>=1;
        }
        return f;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=4;j++)
                scanf("%lld",&p[i][j]),inv[i][j]=quickpow(1-p[i][j],mod-2);
        for(int i=1;i<=4;i++)
            for(int j=1;j<=4;j++)
                scanf("%lld",&w[i][j]);
        dp[0][1]=dp[0][2]=dp[0][3]=dp[0][4]=1;
        for(int k=1;k<=4;k++)
            for(int i=1;i<=n;i++)
            {
                ll p1=(1-p[i][k]),p2=p[i][k];
                for(int j=n;j;j--)
                    dp[j][k]=(p2*dp[j-1][k]+p1*dp[j][k])%mod;
                dp[0][k]=dp[0][k]*(1-p[i][k])%mod;
            }
        for(int i=1;i<=n;i++)//这个人
            for(int j=1;j<=4;j++)//选啥
            {
                if(p[i][j]==0) continue;
                for(int k=1;k<=4;k++)//结果是
                {
                    if(w[k][j]==0) continue;
                    int flag=1,up=(n>>1)+1-(j==k);
                    ll sum=0;
                    if(p[i][k]==1) flag=0;
                    if(flag)
                    {
                        dp[0][k]=dp[0][k]*inv[i][k]%mod;
                        ll p2=p[i][k];
                        for(int l=1;l<up;l++)//退包
                            dp[l][k]=(dp[l][k]-p2*dp[l-1][k])%mod*inv[i][k]%mod;
                        for(int l=up;l<=n;l++)
                        {
                            dp[l][k]=(dp[l][k]-p2*dp[l-1][k])%mod*inv[i][k]%mod;
                            sum+=dp[l][k];
                        }
                    }
                    if(!flag)
                    {
                        for(int i=up+1;i<=n;i++)
                            sum+=dp[i][k];
                    }
                    sum%=mod;
                    (ans[i]+=w[k][j]*sum%mod*p[i][j])%=mod;
                    if(flag)
                    {
                        ll p1=(1-p[i][k]),p2=p[i][k];
                        for(int l=n;l;l--)
                            dp[l][k]=(dp[l][k]*p1+p2*dp[l-1][k])%mod;
                        dp[0][k]=dp[0][k]*(1-p[i][k])%mod;
                    }
                }
            }
        for(int i=1;i<=n;i++)
            printf("%lld
    ",(ans[i]+mod)%mod);
        return 0;
    }
    

    2018.10.21

  • 相关阅读:
    希腊字母写法
    The ASP.NET MVC request processing line
    lambda aggregation
    UVA 10763 Foreign Exchange
    UVA 10624 Super Number
    UVA 10041 Vito's Family
    UVA 10340 All in All
    UVA 10026 Shoemaker's Problem
    HDU 3683 Gomoku
    UVA 11210 Chinese Mahjong
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9827273.html
Copyright © 2011-2022 走看看