[CSP-S模拟测试]:抽卡(概率DP)

2023-10-16 04:50
文章标签 dp csp 模拟 测试 概率 抽卡

本文主要是介绍[CSP-S模拟测试]:抽卡(概率DP),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目描述

水上由岐最近在肝手游,游戏里有一个氪金抽卡的活动。有$n$种卡,每种卡有 3 种颜色。每次抽卡可能什么也抽不到,也可能抽到一张卡。每氪金一次可以连抽 m 次卡,其中前$m−1$次抽到第$i$种卡的概率是$p_i$,什么都抽不到的概率为$1−\sum \limits_{i=1}^n p_i$,如果抽到了卡则这张卡是每种颜色的概率均为$\frac{1}{3}$;最后一次抽到第$i$种卡的概率是$q_i$,什么都抽不到的概率为$1−\sum \limits_{i=1}^n q_i$,如果抽到了卡则这张卡是每种颜色的概率均为$\frac{1}{3}$。她想知道,当每种颜色的每种卡全都抽到时,氪金次数的期望。


输入格式

第一行,两个正整数$n,m$。
第二行,$n$个正整数$\hat{p}_i$,表示$p_i=\dfrac{\hat{p}_i}{100n}$。
第三行,$n$个正整数$\hat{q}_i$,表示$q_i=\dfrac{\hat{q}_i}{100n}$。
请注意,$m=1$时也会输入$p_i$,尽管此时$p_i$并不会被用到。


输出格式

因为输入的概率均为有理数且分母很小,可以证明这个期望可以表示为一个有理数$\frac{x}{y}$,其中$x,y$为互质的正整数且$y\not\equiv 0(\mod 2000000011)$,您只需输出$x\times y^{−1}\mod 2000000011$(其中$2000000011$是一个质数,$y^{−1}$是$y$模$2000000011$的逆元)。您只需在计算中的每一步都用乘逆元来代替除法即可得到这个答案。


样例

样例输入1:

1 1
50
50

样例输出1:

11

样例输入2:

9 11
1 1 1 1 1 1 1 1 1
5 5 5 5 5 5 5 5 5

样例输出2:

1080332495


数据范围与提示

样例2解释:

这个数约等于$700.8844378075970484100784276$。

数据范围:

对于所有数据,$1\leqslant n\leqslant 9,1\leqslant m\leqslant 64,0<\sum \hat{p}_i,\sum \hat{q}_i\leqslant 100n$。
下表中的某些测试点有以下两种特殊性质中的一种或两种,一个测试点满足该性质用$\surd$表示,不满足用$\times$表示。
•性质一:所有$q_i=p_i$。
•性质二:所有$p_i$相等,所有$q_i$相等。


题解

  不同种类的卡之间概率不等,不再等价,但是抽到每种颜色的概率都相等,所以对于每种卡来说不同颜色之间是等价的,只需记录每种颜色当前已经抽出了多少张卡($0\sim 3$张),于是可以用一个$n$位的四进制数来记录,状态数为$4^n$。

  考虑$DP$,设$dp[s][k]$表示当前的四进制数状态为$s$,本次氪金已经抽了$k$次,到结束时的期望氪金次数。当$s$已经包含了所有颜色的所有种类的卡时,$dp[s][k]=0$;否则,当$k=m$时,因为一次氪金抽卡的结束后是另一次氪金抽卡的开始,所以$dp[s][m]=dp[s][0]+1$;否则,记$c(s,i)$表示状态$s$中第$i$种卡片出现了多少种颜色,则$k<m−1$时(其中$t_i$表示)

  则状态转移方程为:$dp[s][k]=\sum \limits_{i=1}^n p_i(\frac{c(s,i)}{3}dp[s][k+1]+(1-\frac{c(s,i)}{3})dp[t_i][k+1])$

  $k=m−1$时将$p_i$换成$q_i$即可。最后答案为$dp[0][m]$(注意$dp[0][0]$表示的是一次氪金抽卡已经开始,$dp[0][m]$才表示还没有开始)。

  然后你可能会想到高斯消元。

  考虑优化,注意到方程组的特殊性,每个变量只依赖另外一个变量。

  首先,$dp[s][m−1]$可以表示成(其中$a_{m−1},b_{m−1}$是可以求出的常量)
  $dp[s][m-1]=a_{m-1}dp[s][m]+b_{m-1}$
  $dp[s][m-2]$可以表示成(其中$c_{m-2},d_{m-2}$是可以求出的常量)
  $dp[s][m-2]=c_{m-2}dp[s][m-1]+d_{m-2}$
  然后将$dp[s][m−1]$代入$dp[s][m−2]$,可以得到
  $dp[s][m-2]=c{m−2}(a_{m−1}dp[s][m]+b_{m−1})+d_{m−2} \\ =c_{m−2}a_{m−1}dp[s][m]+c_{m−2}b_{m−1}+d_{m−2} \\ =a_{m−2}dp[s][m−1]+b_{m−2}$
  也即

  
$\begin{cases} a_{m-2}=c_{m-2}a_{m-1} \\ b_{m-2}=c_{m-2}b_{m-1}+d_{m-2} \end{cases} $
  按$k$从大到小的顺序,可以依次求出$a_k,b_k$,即将$dp[s][k]$全部表示成$dp[s][k]=a_kdp[s][m]+b_k$的形式,最后得到
  $dp[s][0]=a_0dp[s][m]+b_0$
  而
  $dp[s][m]=dp[s][0]+1$
  联立两方程可以解出$dp[s][m]$的值,然后再代入$dp[s][k]=a_kdp[s][k]+b_k$求出所有$dp[s][k]$。

时间复杂度:$\Theta(4^nmn)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
long long n,m,pos,inv;
long long p[12],q[12];
long long dp[300000][100];
long long a[100],b[100];
long long qpow(long long x,long long y)
{long long res=1;while(y){if(y&1)res=res*x%2000000011;x=x*x%2000000011;y>>=1;}return res;
}
int ask(int x,int y){return (x>>(2*y-2))&3;}
int change(int x,int y){return (x^(ask(x,y)<<(2*y-2)))|((ask(x,y)+1)<<(2*y-2));}
int main()
{scanf("%lld%lld",&n,&m);pos=qpow(100*n,2000000009);inv=qpow(3,2000000009);p[0]=q[0]=1;for(int i=1;i<=n;i++){scanf("%lld",&p[i]);p[i]=p[i]*pos%2000000011;p[0]-=p[i];}for(int i=1;i<=n;i++){scanf("%lld",&q[i]);q[i]=q[i]*pos%2000000011;q[0]-=q[i];}p[0]=(p[0]%2000000011+2000000011)%2000000011;q[0]=(q[0]%2000000011+2000000011)%2000000011;for(int i=(1<<(n<<1))-2;i>=0;i--){memset(a,0,sizeof(a));memset(b,0,sizeof(b));a[m-1]=q[0];for(int k=1;k<=n;k++){long long flag=inv*ask(i,k)%2000000011;a[m-1]=(a[m-1]+q[k]*flag%2000000011)%2000000011;if(ask(i,k)!=3)b[m-1]=(b[m-1]+dp[change(i,k)][m]*q[k]%2000000011*(2000000012-flag)%2000000011)%2000000011;}for(int j=m-2;j>=0;j--){a[j]=p[0];for(int k=1;k<=n;k++){long long flag=inv*ask(i,k)%2000000011;a[j]=(a[j]+p[k]*flag%2000000011)%2000000011;if(ask(i,k)!=3)b[j]=(b[j]+dp[change(i,k)][j+1]*p[k]%2000000011*(2000000012-flag)%2000000011)%2000000011;}b[j]=(b[j+1]*a[j]+b[j])%2000000011;a[j]=a[j]*a[j+1]%2000000011;}dp[i][m]=(b[0]+1)*qpow(2000000012-a[0],2000000009)%2000000011;for(int j=0;j<m;j++)dp[i][j]=(a[j]*dp[i][m]+b[j])%2000000011;}printf("%lld",dp[0][m]);return 0;
}

rp++

转载于:https://www.cnblogs.com/wzc521/p/11482933.html

这篇关于[CSP-S模拟测试]:抽卡(概率DP)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/219155

相关文章

SpringBoot中整合RabbitMQ(测试+部署上线最新完整)的过程

《SpringBoot中整合RabbitMQ(测试+部署上线最新完整)的过程》本文详细介绍了如何在虚拟机和宝塔面板中安装RabbitMQ,并使用Java代码实现消息的发送和接收,通过异步通讯,可以优化... 目录一、RabbitMQ安装二、启动RabbitMQ三、javascript编写Java代码1、引入

Nginx设置连接超时并进行测试的方法步骤

《Nginx设置连接超时并进行测试的方法步骤》在高并发场景下,如果客户端与服务器的连接长时间未响应,会占用大量的系统资源,影响其他正常请求的处理效率,为了解决这个问题,可以通过设置Nginx的连接... 目录设置连接超时目的操作步骤测试连接超时测试方法:总结:设置连接超时目的设置客户端与服务器之间的连接

Golang的CSP模型简介(最新推荐)

《Golang的CSP模型简介(最新推荐)》Golang采用了CSP(CommunicatingSequentialProcesses,通信顺序进程)并发模型,通过goroutine和channe... 目录前言一、介绍1. 什么是 CSP 模型2. Goroutine3. Channel4. Channe

如何测试计算机的内存是否存在问题? 判断电脑内存故障的多种方法

《如何测试计算机的内存是否存在问题?判断电脑内存故障的多种方法》内存是电脑中非常重要的组件之一,如果内存出现故障,可能会导致电脑出现各种问题,如蓝屏、死机、程序崩溃等,如何判断内存是否出现故障呢?下... 如果你的电脑是崩溃、冻结还是不稳定,那么它的内存可能有问题。要进行检查,你可以使用Windows 11

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

字节面试 | 如何测试RocketMQ、RocketMQ?

字节面试:RocketMQ是怎么测试的呢? 答: 首先保证消息的消费正确、设计逆向用例,在验证消息内容为空等情况时的消费正确性; 推送大批量MQ,通过Admin控制台查看MQ消费的情况,是否出现消费假死、TPS是否正常等等问题。(上述都是临场发挥,但是RocketMQ真正的测试点,还真的需要探讨) 01 先了解RocketMQ 作为测试也是要简单了解RocketMQ。简单来说,就是一个分

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

hdu4865(概率DP)

题意:已知前一天和今天的天气概率,某天的天气概率和叶子的潮湿程度的概率,n天叶子的湿度,求n天最有可能的天气情况。 思路:概率DP,dp[i][j]表示第i天天气为j的概率,状态转移如下:dp[i][j] = max(dp[i][j, dp[i-1][k]*table2[k][j]*table1[j][col] )  代码如下: #include <stdio.h>#include