CF908D New Year and Arbitrary Arrangement 题解

题目传送门

题目大意: 给出 k , p a , p b k,pa,pb k,pa,pb,一开始有一个空序列,每次有 p a p a + p b \frac {pa} {pa+pb} pa+pbpa 的概率在末尾放一个 a a a,有 p b p a + p b \frac {pb} {pa+pb} pa+pbpb 的概率在末尾放一个 b b b,当存在 k k k 个形如 a b ab ab 的子序列时停止,问最后期望有多少个 a b ab ab 子序列。

题解

值得注意的是,同一个 a a a 可以存在于多个子序列 a b ab ab 中, b b b 也是。

那么每一次放 b b b 时,就要考虑到前面有多少个 a a a,假如有 j j j 个,那么子序列数量就要加 j j j。那么就能顺理成章的得到 d p dp dp 数组的定义:设 f [ i ] [ j ] f[i][j] f[i][j] 表示有 i i i 个子序列, j j j a a a 的序列的期望答案,方程为:
f [ i ] [ j ] = p a p a + p b f [ i ] [ j + 1 ] + p b p a + p b f [ i + j ] [ j ] f[i][j]=\frac {pa} {pa+pb}f[i][j+1]+\frac {pb} {pa+pb}f[i+j][j] f[i][j]=pa+pbpaf[i][j+1]+pa+pbpbf[i+j][j]

最后,还要考虑到你是非酋的情况,有可能最后放了很多个 a a a 都放不出一个 b b b,导致 j j j 太大然后爆炸,于是我们需要判断,当 i + j ≥ k i+j\geq k i+jk 时,此时但凡只要来一个 b b b 就能停止。

x = p a p a + p b , y = p b p a + p b x=\frac {pa} {pa+pb},y=\frac {pb} {pa+pb} x=pa+pbpa,y=pa+pbpb于是有:
f [ i ] [ j ] = i + j + 0 y + 1 x y + 2 x 2 y + 3 x 3 y + . . . = i + j + x y ( 1 + 2 x + 3 x 2 + 4 x 3 + . . . ) \begin{aligned} f[i][j]&=i+j+0y+1xy+2x^2y+3x^3y+...\\ &=i+j+xy(1+2x+3x^2+4x^3+...)\\ \end{aligned} f[i][j]=i+j+0y+1xy+2x2y+3x3y+...=i+j+xy(1+2x+3x2+4x3+...)

里面这个柿子是个经典的数列求和,学过生成函数的肯定很眼熟,推导一下就是:
1 + 2 x + 3 x 2 + 4 x 3 + . . . = ( 1 + x + x 2 + x 3 + . . . ) 2 1+2x+3x^2+4x^3+...=(1+x+x^2+x^3+...)^2 1+2x+3x2+4x3+...=(1+x+x2+x3+...)2

右边是一个等比数列,那就好办了,设最后一项为 n n n,则有 1 + x + x 2 + x 3 + . . . = 1 − x n 1 − x 1+x+x^2+x^3+...=\frac {1-x^n} {1-x} 1+x+x2+x3+...=1x1xn

由于 0 < x < 1 0<x<1 0<x<1 n n n 趋于无穷大,所以 x n x^n xn 趋于 0 0 0,不妨就当成 0 0 0,就得到 1 + x + x 2 + x 3 + . . . = 1 1 − x 1+x+x^2+x^3+...=\frac 1 {1-x} 1+x+x2+x3+...=1x1,于是那个数列就等于 1 ( 1 − x ) 2 \frac 1 {(1-x)^2} (1x)21

因为 x + y = 1 x+y=1 x+y=1,所以 1 ( 1 − x ) 2 = 1 y 2 \frac 1 {(1-x)^2}=\frac 1 {y^2} (1x)21=y21

带回原柿子得到:
f [ i ] [ j ] = i + j + x y × 1 y 2 = i + j + p a p b f[i][j]=i+j+xy\times \frac 1 {y^2}=i+j+\frac {pa} {pb} f[i][j]=i+j+xy×y21=i+j+pbpa

于是就可以 d p dp dp 了,以及, d p dp dp 的时候从 f [ 0 ] [ 1 ] f[0][1] f[0][1] 开始,避免一直出 b b b 而毫无进展的情况。

代码如下:

#include <cstdio>
#include <cstring>
#define mod 1000000007

int k,a,b,inv_a,inv_b,inv_ab;
int ksm(int x,int y)
{
	int re=1;
	while(y)
	{
		if(y&1)re=1ll*re*x%mod;
		x=1ll*x*x%mod;y>>=1;
	}
	return re;
}
#define inv(x) ksm(x,mod-2)
int f[1010][1010];
int dp(int i,int j)
{
	if(i+j>=k)return (i+j+1ll*a*inv_b%mod)%mod;
	if(f[i][j]!=-1)return f[i][j];
	return f[i][j]=(1ll*a*inv_ab%mod*dp(i,j+1)+1ll*b*inv_ab%mod*dp(i+j,j))%mod;
}

int main()
{
	scanf("%d %d %d",&k,&a,&b);
	inv_a=inv(a);inv_b=inv(b);inv_ab=inv(a+b);
	memset(f,-1,sizeof(f));
	printf("%d",dp(0,1));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值