• 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] 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;
    }
    
  • 相关阅读:
    Golang 函数
    Golang type
    Golang 分支控制和循环
    Golang 字符型
    Golang运算符
    final 和 static 的区别
    Golang标识符命名规则
    Golang值类型与引用类型
    Golang指针
    启动 jvm 参数小总结
  • 原文地址:https://www.cnblogs.com/Hs-black/p/13847748.html
Copyright © 2020-2023  润新知