CF908D New Year and Arbitrary Arrangement

题意

给定三个数 k k ,pa, pb p b
每次有 papa+pb p a p a + p b 的概率往后面添加一个’ a a
每次有pbpa+pb的概率往后面添加一个’ b b
当出现了k个形如 ab a b 的子序列(不用连续)时停止
求最后的 ab a b 序列的期望数
答案对 109+7 10 9 + 7 取膜

Sol

f[i][j] f [ i ] [ j ] 表示前面有 i i a j j ab的期望 ab a b 的对数
倒着来转移
显然
f[i][j]=f[i+1][j]papa+pb+f[i][i+j]pbpa+pb f [ i ] [ j ] = f [ i + 1 ] [ j ] ∗ p a p a + p b + f [ i ] [ i + j ] ∗ p b p a + p b
答案就是 f[0][0] f [ 0 ] [ 0 ]
然而 f[0][0]=f[1][0]papa+pb+f[0][0]pbpa+pb f [ 0 ] [ 0 ] = f [ 1 ] [ 0 ] ∗ p a p a + p b + f [ 0 ] [ 0 ] ∗ p b p a + p b
不好算
移项后得到 f[0][0]=f[1][0] f [ 0 ] [ 0 ] = f [ 1 ] [ 0 ]
所以输出 f[1][0] f [ 1 ] [ 0 ] 就好了

然而串长是无限的, a a 的个数也是无限的,ab的对数无限,它们可以到
这就很不好做了了

但是你会发现,当 a a 无穷多时,放一个b ab a b 对数就会超过 k k ,显然直接就停了
对于f[i][j],当 i+j>=k i + j >= k 时,考虑它的期望
也就是 f[i][j]=pbpa+pbl=0(papa+pb)l(i+j+l) f [ i ] [ j ] = p b p a + p b ∑ l = 0 ∞ ( p a p a + p b ) l ( i + j + l )

S=l=0(papa+pb)l(i+j+l) S = ∑ l = 0 ∞ ( p a p a + p b ) l ( i + j + l )

papa+pbS=l=0(papa+pb)l+1(i+j+l) p a p a + p b S = ∑ l = 0 ∞ ( p a p a + p b ) l + 1 ( i + j + l )
两式相减得
(1papa+pb)S=(i+j)+l=1(papa+pb)l ( 1 − p a p a + p b ) S = ( i + j ) + ∑ l = 1 ∞ ( p a p a + p b ) l

l=1(papa+pb)l ∑ l = 1 ∞ ( p a p a + p b ) l
也可以类似处理
得到就是
papa+pb(papa+pb)1papa+pb=papb p a p a + p b − ( p a p a + p b ) ∞ 1 − p a p a + p b = p a p b
带回去
(1papa+pb)S=(i+j)+papb ( 1 − p a p a + p b ) S = ( i + j ) + p a p b

pbpa+pbS=(i+j)+papb p b p a + p b S = ( i + j ) + p a p b

所以
f[i][j]=pbpa+pbS=(i+j)+papb f [ i ] [ j ] = p b p a + p b S = ( i + j ) + p a p b

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int Zsy(1e9 + 7);

int k, pa, pb, invb, inv, f[1005][1005], Pa, Pb;

IL int Input(){
    RG int x = 0, z = 1; RG char c = getchar();
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x * z;
}

IL int Pow(RG ll x, RG ll y){
    RG ll ret = 1;
    for(; y; y >>= 1, x = x * x % Zsy)
        if(y & 1) ret = ret * x % Zsy;
    return ret;
}

int main(RG int argc, RG char *argv[]){
    k = Input(), pa = Input(), pb = Input();
    invb = Pow(pb, Zsy - 2), inv = Pow(pa + pb, Zsy - 2);
    Pa = 1LL * pa * inv % Zsy, Pb = 1LL * pb * inv % Zsy;
    for(RG int i = k; i; --i)
        for(RG int j = k; ~j; --j)
            if(i + j >= k) f[i][j] = ((i + j) + 1LL * pa * invb % Zsy + Zsy) % Zsy;
            else f[i][j] = (1LL * f[i + 1][j] * Pa % Zsy + 1LL * f[i][j + i] * Pb % Zsy) % Zsy;
    printf("%d\n", f[1][0]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值