CF908D New Year and Arbitrary Arrangement(期望 dp)

CF908D New Year and Arbitrary Arrangement(期望 dp)

题目大意

给定三个数 \(k,pa,pb\)

每次有 \(\dfrac{pa}{pa+pb}\) 的概率往后面添加一个 a

每次有 \(\dfrac{pb}{pa+pb}\) 的概率往后面添加一个 b

当出现了 \(k\) 个形如 \(ab\) 的子序列(不用连续)时停止。

求最后 ab 序列的期望数。 答案对 \(10^9+7\) 取模。

Translated by yybyyb

数据范围

\[1 \le k \le 1000 \]

解题思路

切了这道题感觉自信++,好像事和别人不一样的正推方法呢

考虑动态规划,容易发现无限放 a 和 b 的情况不是很好处理。但是!我们就是要正着推!

首先容易发现开头放多少个 b 对答案都没有影响,所以我们钦定第一个放 a。

\(f[x][y]\) 表示放了 x 个 a,获得了 y 个子序列的概率,枚举下一个放 a 还是 b 有

\[f[x+1][y] += f[x][y] \times P_a\\ f[x][y+x] += f[x][y] \times P_b \]

那么当 \(y + x \ge k\) 时,直接把概率乘上 \(y+x\) 加到答案上。

还有一个问题,当 dp 到 \(f[k][x]\) 时,显然再加入一个 b 都会满足条件,但是仍然存在可能使得无限放 a 的可能,所以我们稍微推一下式子即可,枚举放了几个 a,有

\[E(x)=\sum_{i=0}P_a^i P_b\times(k+i)\\ =k+P_b\times\sum_{i=0}P_a^i\times i \]

如何计算 \(P_a^i\times i\) 可以考虑等比数列求和的基本知识。

最后算出得 \(E(x) = k -1 + \frac 1{P_b}\)

如果你想看等比数列求和基本知识可以继续阅读

\[\text{设 } T= \sum_{i=0}P_a^i\times i\\ E(x)=k+(1-P_a)T\\ P_aT=\sum_{i=1}P_a^i(i-1)\\ T-P_aT=\sum_{i=1}P_a^i=\frac {1}{1-P_a}-1=\frac {1}{P_b}-1\\ \therefore E(x)=k+(1-P_a)T=k-1+\frac {1}{P_b} \]

代码就很短了。

/*
     />  フ
     |  _  _|
     /`ミ _x 彡
     /      |
    /   ヽ   ?
 / ̄|   | | |
 | ( ̄ヽ__ヽ_)_)
 \二つ
 */

#include <queue>
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MP make_pair
#define ll long long
#define fi first
#define se second
using namespace std;

template <typename T>
void read(T &x) {
    x = 0; bool f = 0;
    char c = getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
    for (;isdigit(c);c=getchar()) x=x*10+(c^48);
    if (f) x=-x;
}

template<typename F>
inline void write(F x, char ed = '\n') {
	static short st[30];short tp=0;
	if(x<0) putchar('-'),x=-x;
	do st[++tp]=x%10,x/=10; while(x);
	while(tp) putchar('0'|st[tp--]);
	putchar(ed);
}

template <typename T>
inline void Mx(T &x, T y) { x < y && (x = y); }

template <typename T>
inline void Mn(T &x, T y) { x > y && (x = y); }

const int P = 1e9 + 7;
ll fpw(ll x, ll mi) {
	ll res = 1;
	for (; mi; mi >>= 1, x = x * x % P)
		if (mi & 1) res = res * x % P;
	return res;
}

const int N = 2005;
ll k, pa, pb;
ll f[N][N];
int main() {
	read(k), read(pa), read(pb);
	ll t = fpw(pa + pb, P - 2);
	pa = pa * t % P, pb = pb * t % P;
	f[1][0] = 1; ll ans = 0;
	for (int i = 1;i < k; i++) {
		for (int j = 0;j < k; j++) {
			f[i+1][j] = (f[i+1][j] + f[i][j] * pa) % P;
			if (j + i < k) f[i][j+i] = (f[i][j+i] + f[i][j] * pb) % P;
			else ans = (ans + (j + i) * f[i][j] % P * pb) % P;
		}
	}
	t = fpw(pb, P - 2) * pa % P;
	for (int i = 0;i < k; i++) 
		ans = (ans + f[k][i] * (k + i + t)) % P;
	write(ans);
	return 0;
}
posted @ 2020-10-20 17:26  Hs-black  阅读(162)  评论(0编辑  收藏  举报