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] imes P_a\
f[x][y+x] += f[x][y] imes 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 imes(k+i)\
=k+P_b imessum_{i=0}P_a^i imes i
]
如何计算 (P_a^i imes i) 可以考虑等比数列求和的基本知识。
最后算出得 (E(x) = k -1 + frac 1{P_b})
如果你想看等比数列求和基本知识可以继续阅读
[ ext{设 } T= sum_{i=0}P_a^i imes 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\
herefore 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 = '
') {
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;
}