题目描述

水上由岐最近在肝手游,游戏里有一个氪金抽卡的活动。有$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++

[CSP-S模拟测试]:抽卡(概率DP)的更多相关文章

  1. [CSP-S模拟测试]:玩具(概率DP)

    题目描述 这个故事发生在很久以前,在$IcePrincess\text{_}1968$和$IcePrince\text{_}1968$都还在上幼儿园的时候. $IcePrince\text{_}196 ...

  2. [CSP-S模拟测试]:Seat(概率DP+数学)

    题目描述 有$n+2$个座位等距地排成一排,从左到右编号为$0$至$n+1$.最开始时$0$号以及$n+1$号座位上已经坐了一个小$G$,接下来会有$n$个小$G$依次找一个空座位坐下.由于小$G$们 ...

  3. [CSP-S模拟测试]:B(期望DP)

    题目传送门(内部题151) 输入格式 第一行一个整数$N$. 第二行$N$个整数,第$i$个为$a_i$. 输出格式 一行一个整数,表示答案.为避免精度误差,答案对$323232323$取模. 即设答 ...

  4. [CSP-S模拟测试]:军训队列(DP+乱搞)

    题目描述 有$n$名学生参加军训,军训的一大重要内容就是走队列,而一个队列的不规整程度是该队中最高的学生的身高与最矮的学生的身高差值的平方.现在要将$n$名参加军训的学生重新分成$k$个队列,每个队列 ...

  5. [CSP-S模拟测试]:赤壁情(DP)

    前赤壁赋 壬戌之秋,七月既望,苏子与客泛舟游于赤壁之下.清风徐来,水波不兴.举酒属客,诵明月之诗,歌窈窕之章.少焉,月出于东山之上,徘徊于斗牛之间.白露横江,水光接天.纵一苇之所如,凌万顷之茫然.浩浩 ...

  6. [CSP-S模拟测试]:chemistry(期望DP+组合数学)

    题目传送门(内部题27) 输入格式 第一行有$4$个整数$n,k,p,q$.第二行有$n$个整数$a_i$.接下来有$n-1$行,每行有两个整数$u,v$,表示$u$与$v$之间通过化学单键连接. 输 ...

  7. [CSP-S模拟测试]:抛硬币(DP)

    题目背景 小$A$和小$B$是一对好朋友,他们经常一起愉快的玩耍.最近小$B$沉迷于**师手游,天天刷本,根本无心搞学习.但是小$B$已经入坑了几个月,却一次都没有抽到$SSR$,让他非常怀疑人生.勤 ...

  8. [CSP-S模拟测试]:走路(期望DP+分治消元)

    题目传送门(内部题100) 输入格式 第一行两个整数$n,m$,接下来$m$行每行两个整数$u,v$表示一条$u$连向$v$的边.不保证没有重边和自环. 输出格式 $n-1$行每行一个整数,第$i$行 ...

  9. [CSP-S模拟测试]:密码(数位DP+库默尔定理)

    题目描述 为了揭穿$SERN$的阴谋,$Itaru$黑进了$SERN$的网络系统.然而,想要完全控制$SERN$,还需要知道管理员密码.$Itaru$从截获的信息中发现,$SERN$的管理员密码是两个 ...

随机推荐

  1. 后端技术杂谈3:Lucene基础原理与实践

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  2. python中split()函数的用法

    函数:split() Python中有split()和os.path.split()两个函数,具体作用如下:split():拆分字符串.通过指定分隔符对字符串进行切片,并返回分割后的字符串列表(lis ...

  3. Linux sudo 详解

    简单的说,sudo 是一种权限管理机制,管理员可以授权于一些普通用户去执行一些 root 执行的操作,而不需要知道 root 的密码.严谨些说,sudo 允许一个已授权用户以超级用户或者其它用户的角色 ...

  4. Oracle 简单统计示例

    有数据如下: eg1:现在需要统计所有男性人员数量,所有女性人员数量,sclassno=10000的男性人员的总年龄,年龄大于20的女性人员数量 ----sign( number )/*If numb ...

  5. Oralce-PL/SQL编程-游标

    PL/SQL(Procedural Language/SQL)是Oracle在数据库中引入的一种过程化编程语言. PL/SQL块结构 声明部分 执行部分(必须的) 异常处理部分 [declare] - ...

  6. 项目搭建(二):NUnit&TestStack.White

    一.单元测试框架NUnit NUnit是所有.net语言的单元测试框架.使用C#语言编写. 测试框架:NUnit3 1. 安装NuGet包管理器 2. 在NuGet中安装NUnit.NUnit.Con ...

  7. spring boot 尚桂谷学习笔记09 数据访问

    springboot 与数据库访问 jdbc, mybatis, spring data jpa,  1.jdbc原生访问 新建项目 使用 springboot 快速构建工具 选中 web 组件 sq ...

  8. 递归算法介绍及Java应用实战

    什么是递归算法 递归算法是把问题转化为规模缩小了的同类问题的子问题,然后递归调用函数(或过程)来表示问题的解.一个过程(或函数)直接或间接调用自己本身,这种过程(或函数)叫递归过程(或函数). 递归过 ...

  9. CSS3 3D旋转下拉菜单--兼容性不太好

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...

  10. BUUCTF weirdlist 一路到底

    Weird list 这题恶心的一批 给了一堆列表 这...这是人做的题吗... 放飞自我,打开脑洞 把‘1’空出来,其他数字换为‘*’画出来 然后看到了flag,但是 这...这是什么flag,ag ...