zoukankan      html  css  js  c++  java
  • Ybt#452序列合并【期望dp】

    正题

    题目链接:https://www.ybtoj.com.cn/contest/113/problem/2


    题目大意

    一个空序列,每次往末尾加入一个\([1,m]\)中的随机一个数。如果末尾两个数相同都为\(x\)\((x<t)\),那么将它们合并成\(x+1\)

    如果序列长度为\(n\)且无法合并则结束,求序列期望和。

    \(n,m\in[1,10^3],t\in[1,10^9]\)


    解题思路

    首先显然地\(t=min\{n+m-1,t\}\)

    之后考虑序列中的每一个位置可能的数,因为每种情况都有可能,所以我们需要算概率先,设\(p_{i,j}\)表示剩余\(i\)个位置时出现\(j\)的概率,那么有\(p_{i,j}=\frac1m\times [j\leq m]+p_{i,j-1}^2\)(直接出现或者合并出来)。

    \(p_{i,j}\times q_{i,j}\)表示剩下\(i\)个位置且第一个最终是\(j\)的概率,那么有\(q_{i,j}=1-p_{i-1,j}\times [j<t]\)\(q_{i,j}\)就表示在出现了\(j\)的前提下不变的概率,减去会变的概率就好了)。

    但是因为每个位置的概率不是独立的,所以不能直接用这个来算答案。

    \(p_{i,j}\times g_{i,j}\)表示在剩下\(i\)个位置且第一个最终是\(j\)时和的期望和(注意期望=概率*次数),\(p_{i,j}\times f_{i,j}\)表示剩下\(i\)个位置时第一个出现过\(j\)的情况的期望和,\(ans_i\)表示剩下\(i\)个位置时的期望和。

    那么有

    \[ans_i=\sum_{j=1}^{t}p_{i,j}\times g_{i,j} \]

    考虑\(g\)的递推式有

    \[g_{i,j}=q_{i,j}\times j+ans_{i-1}-p_{i-1,j}\times f_{i-1,j} \]

    (有\(q_{i,j}\)的概率最终是\(j\),填完剩下的,且下一个不能出现\(j\)
    考虑\(f\)的递推式有

    \[f_{i,j}=g_{i,j}+(1-q_{i,j})f_{i,j+1} \]

    (第一种是最终不变,第二种是变成了\(j+1\)的情况)

    这样就可以递推了,时间复杂度\(O(n^2)\)


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const ll N=2100,P=1e9+7;
    ll n,m,t,p[N][N],q[N][N],g[N][N],f[N][N],ans[N];
    ll power(ll x,ll b){
    	ll ans=1;
    	while(b){
    		if(b&1)ans=ans*x%P;
    		x=x*x%P;b>>=1;
    	}
    	return ans;
    }
    signed main()
    {
    	freopen("sequence.in","r",stdin);
    	freopen("sequence.out","w",stdout);
    	scanf("%lld%lld%lld",&n,&m,&t);
    	ll inv=power(m,P-2);
    	t=min(t,n+m-1);
    	for(ll i=1;i<=n;i++)
    		for(ll j=1;j<=t;j++){
    			p[i][j]=(inv*(j<=m)+p[i-1][j-1]*p[i][j-1]%P)%P;
    			q[i][j]=(1-(j<t)*p[i-1][j]+P)%P;
    		}
    	for(ll i=1;i<=n;i++){
    		for(ll j=t;j>=1;j--){
    			if(j!=t)
    				g[i][j]=(q[i][j]*j%P+ans[i-1]-f[i-1][j]*p[i-1][j]%P+P)%P;
    			else
    				g[i][j]=(q[i][j]*j%P+ans[i-1])%P;
    			f[i][j]=(g[i][j]%P+(1-q[i][j])*f[i][j+1]%P)%P;
    			(ans[i]+=g[i][j]*p[i][j])%=P;
    		}
    	}
    	printf("%lld\n",ans[n]);
    	return 0;
    }
    
  • 相关阅读:
    第一章:简介
    2018年10月底新公司
    第四章:集成
    第三章:如何建模服务
    第二章:演化架构师
    第一章:微服务
    4、工厂模式
    5、单例模式
    8、模板方法模式
    3、字典介绍
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14402054.html
Copyright © 2011-2022 走看看