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 \lfloor\frac{n}{2}\rfloor\) ,则所有人得 \(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) $
 - \(\sum\limits_{j=1}^4 p_{i,j} \equiv 1 (\bmod 998244353)(1\le i \le n)\)
 
各个测试点的性质如下
| 测试点编号 | n | 特殊性质 | 
|---|---|---|
| \(1\) | \(\le 2\) | |
| \(2\) | \(\le 10\) | \(p_{i,3}=p_{i,4}=0,(1\le i \le n)\) | 
| \(3\) | \(\le 10\) | |
| \(4,5\) | \(\le 100\) | \(p_{i,3}=p_{i,4}=0,(1\le i \le n)\) | 
| \(6,7\) | \(\le 100\) | \(p_{i,4}=0(1\le i \le n)\) | 
| \(8,9,10,11\) | \(\le 100\) | |
| \(12\sim20\) | \(\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\n",(ans[i]+mod)%mod);
    return 0;
}
2018.10.21
nowcoder 提高组模拟赛 选择题 解题报告的更多相关文章
- nowcoder 提高组模拟赛 最长路 解题报告
		
最长路 链接: https://www.nowcoder.com/acm/contest/178/A 来源:牛客网 题目描述 有一张 \(n\) 个点 \(m\) 条边的有向图,每条边上都带有一个字符 ...
 - NOIP2017提高组 模拟赛15(总结)
		
NOIP2017提高组 模拟赛15(总结) 第一题 讨厌整除的小明 [题目描述] 小明作为一个数学迷,总会出于数字的一些性质喜欢上某个数字,然而当他喜欢数字k的时候,却十分讨厌那些能够整除k而比k小的 ...
 - NOIP2017提高组 模拟赛13(总结)
		
NOIP2017提高组 模拟赛13(总结) 第一题 函数 [题目描述] [输入格式] 三个整数. 1≤t<10^9+7,2≤l≤r≤5*10^6 [输出格式] 一个整数. [输出样例] 2 2 ...
 - ZROI提高组模拟赛05总结
		
ZROI提高组模拟赛05总结 感觉是目前为止最简单的模拟赛了吧 但是依旧不尽人意... T1 有一半的人在30min前就A掉了 而我花了1h11min 就是一个简单的背包,我硬是转化了模型想了好久,生 ...
 - NOIP2017提高组模拟赛 10 (总结)
		
NOIP2017提高组模拟赛 10 (总结) 第一题 机密信息 FJ有个很奇怪的习惯,他把他所有的机密信息都存放在一个叫机密盘的磁盘分区里,然而这个机密盘中却没有一个文件,那他是怎么存放信息呢?聪明的 ...
 - NOIP2017提高组模拟赛 8(总结)
		
NOIP2017提高组模拟赛 8(总结) 第一题 路径 在二维坐标平面里有N个整数点,Bessie要访问这N个点.刚开始Bessie在点(0,0)处. 每一步,Bessie可以走到上.下.左.右四个点 ...
 - NOIP2017提高组模拟赛 9 (总结)
		
NOIP2017提高组模拟赛 9 (总结) 第一题 星星 天空中有N(1≤N≤400)颗星,每颗星有一个唯一的坐标(x,y),(1≤x,y ≤N).请计算可以覆盖至少K(1≤K≤N)颗星的矩形的最小面 ...
 - NOIP2017提高组模拟赛 7(总结)
		
NOIP2017提高组模拟赛 7(总结) 第一题 斯诺克 考虑这样一个斯诺克球台,它只有四个袋口,分别在四个角上(如下图所示).我们把所有桌子边界上的整数点作为击球点(除了4个袋口),在每个击球点我们 ...
 - NOIP2017提高组模拟赛5 (总结)
		
NOIP2017提高组模拟赛5 (总结) 第一题 最远 奶牛们想建立一个新的城市.它们想建立一条长度为N (1 <= N <= 1,000,000)的 主线大街,然后建立K条 (2 < ...
 
随机推荐
- 《python编程从入门到实践》第六章笔记
			
1.字典 字典:一系列键-值对,每一个键都与每一个值相关联.与键相关联的值可以是数字.字符串.列表和字典. 最简单的字典只有一个键值对. eg: alien = {'color':'green','p ...
 - tarnado源码解析系列一
			
目录 tarnado tarnado源码安装 tarnado测试程序 application类的解析 一. tarnado简介 最近在学习Python,无意间接触到的tarnado,感觉tarnado ...
 - Fabric go sdk初始化所需证书解析
			
fabric sdk go 提供的官方文档少之又少,要想入门,主要就靠研究官方的e2e系列示例,这真的是一件挺无奈的事情.没法子,只能硬着头皮上了.研究发现,e2e这个例子是通过cryptogen生成 ...
 - ABAP CDS - 字符串函数
			
下表显示了ABAP CDS中CDS视图中字符串的潜在SQL函数,以及对参数的要求.函数的含义可以在字符串的SQL函数下找到. 函数 参数类型 返回类型 CONCAT(arg1, arg2) See b ...
 - .Net 面试题 汇总(一)
			
1.@page指令只能在_aspx___文件(填写扩展名)中使用,而@Control指令只能用在_ascx___文件(填写扩展名)中使用. 2.说明控件DataGrid,DataTable,DataV ...
 - C# 控制台应用程序输出颜色字体
			
最佳解决方案的代码: static void Main(string[] args) { Console.ForegroundColor = ConsoleColor.Green; Console.W ...
 - Ubuntu 手机 app开发学习0
			
# 相关网址 http://developer.ubuntu.com/zh-cn/apps/sdk/ 0. 环境搭建 首选需要一个Ubuntu 14.04操作系统.没啥好讲的,直接安装了一个虚拟机. ...
 - python 基础篇 11 函数进阶----装饰器
			
11. 前⽅⾼能-装饰器初识本节主要内容:1. 函数名的运⽤, 第⼀类对象2. 闭包3. 装饰器初识 一:函数名的运用: 函数名是一个变量,但他是一个特殊变量,加上括号可以执行函数. ⼆. 闭包什么是 ...
 - python3学习之路_day1
			
登录程序1.输入用户名密码2.认证成功后显示欢迎信息3.输错三次后锁定 #!/usr/bin/env python #_*_coding:utf-8_*_ #by anthor gushiren 20 ...
 - liunx运维必备150个基础命令
			
经过上次的面试,总结了一下的linux系统常用命令: 命令 功能说明 线上查询及帮助命令(2个) man 查看命令帮助,命令的词典,更复杂的还有info,但不常用. help 查看Linux内置命令的 ...