CF908D题解

题意

一个空串,每次操作 \(p_a\) 概率加入a \(p_b\) 概率加入 b,当子序列 ab(不必连续)个数 \(\ge k\) 时停止,问最终字符串中子序列 ab 的期望个数。
\(k \le 1000\)

题解

思路

首先发现字符串长度无限制,不能用传统总和除以总方案来算期望。
研究字符串形成方案,发现:

每个字符串最后一定是加 \(m\)a,然后加入 \(1\)b

设之前有 \(cnt\)ab\(n\)\(a\) ,最终字符串的ab个数就是\(cnt+n+m\) ,而与之前具体状态无关。因此只要知道之前有多少个 aab和此时的概率,然后枚举一下 \(m\) 算一下即可,奶一口最后可以用和式化掉。

做法

\(f_{i,j}\) 表示有 \(i\)a\(j\)ab 的概率,因为最开始加一堆 b 没意义,直接钦定第一个为 a 。而为了不重,我们枚举添加最后一个 b 之前的状态。

\[f_{i,j}=f_{i-1,j}\times p_a + f_{i,j-i} \times p_b\\ f_{1,0} = 1\\ Ans=\sum\limits_{i=1}^{+\infty}\sum_{i+j\ge k}^{k-1} f_{i,j} \times p_b \times (i+j) \]

第一维没有上界没法做,发现:

在最后一次加 aa...ab 之前, a 的个数一定小于 \(k\)

对于这一部分暴力算。对于 \(i\ge k\) ,我们枚举之前 ab 个数,记为 \(j\) ,然后枚举总共有 \(k+i\)a,贡献为:

\[\begin{align*} &\quad\ \ f_{k,j}\times\sum\limits_{i=0}^{+\infty} (p_a)^i \times p_b \times (i+j+k)\\ &=f_{k,j}\times p_b\times((j+k)\times\sum\limits_{i=0}^{+\infty} (p_a)^i+\sum_{i=0}^{+\infty}i\times (p_a)^i)\\ &=f_{k,j}\times p_b\times (\frac{j+k}{1-p_a}+\frac{p_a}{(1-p_a)^2})\\ &=f_{k,j}\times p_b\times(\frac{j+k}{p_b}+\frac{p_a}{(p_b)^2})\\ &=f_{k,j}\times (j+k+\frac{p_a}{p_b}) \end{align*} \]

最后答案就是

\[Ans=\sum\limits_{i=1}^{k-1}\sum_{j=k-i}^{k-1} f_{i,j} \times p_b \times (i+j)+\sum_{i=0}^{k-1} f_{k,i}\times(i+k+\frac{p_a}{p_b}) \]

Code

#include<bits/stdc++.h>
#define ri register int
#define ll long long
using namespace std;
const int maxn = 1e3 + 10,mod = 1e9 + 7;
inline ll qp(ll x,int k){
	ll res = 1;
	while(k){
		if(k & 1) res = res * x % mod;
		x = x * x % mod;
		k >>= 1;
	}
	return res;
}
ll f[maxn][maxn];
int pa,pb,s,k;
int main(){
	scanf("%d%d%d",&k,&pa,&pb);
	s = pa + pb;
	pa = pa * qp(s,mod - 2) % mod,pb = pb * qp(s,mod - 2) % mod;
	ll inv = pa * qp(pb,mod - 2) % mod;
	f[1][0] = 1;
	for(ri i = 1;i <= k;++i)
		for(ri j = 0;j < k;++j){
			if(i == 1 && j == 0) continue;
			f[i][j] = f[i-1][j] * pa % mod;
			if(j >= i) f[i][j] = (f[i][j] + f[i][j-i] * pb % mod) % mod;
		}
	ll ans = 0;
	for(ri i = 1;i < k;++i)
		for(ri j = k-i;j < k;++j)
			ans = (ans + f[i][j] * pb % mod * (i+j) % mod) % mod;
	for(ri i = 0;i < k;++i) ans = (ans + f[k][i] * (i+k+inv) % mod) % mod;
	printf("%lld\n",ans);
	return 0;
}

总结

这道题区别于套路期望计数,需要发现题目的性质然后设出 \(DP\) ,再发现性质分类讨论得到最后的式子。更加灵活、偏向思维,而不是直接生成函数化式子。在两个和式中对于基本功也有考察。

posted @ 2021-11-04 22:36  Lumos壹玖贰壹  阅读(30)  评论(0编辑  收藏  举报