穿越万年的轮回[期望dp]

在这里插入图片描述
首先我们设置 d p i , 0 / 1 , 0 / 1 dp_{i,0/1,0/1} dpi,0/1,0/1表示经过 i i i次操作之后开头为 r e d / e d r red/edr red/edr,结尾为 r e d / e d r red/edr red/edr的串的期望 r e d red red字符串个数。
然后我们考虑转移:
首先我们要来思考一下期望的本质,这样一个状态,我们以 d p i , 0 , 0 dp_{i,0,0} dpi,0,0为例,里面可能有很多种情况,比如串 " r e d r e d " "redred" "redred"和串 " r e d e d r r e d " "rededrred" "rededrred"每一种有一个概率和贡献,假设有 n n n种情况,每一种的概率是 p i p_i pi,贡献是 X i X_i Xi,那么
d p i , 0 , 0 = ∑ i = 1 p i X i dp_{i,0,0}=\sum_{i=1}p_iX_i dpi,0,0=i=1piXi
那么我们考虑在这个状态后面接上一个 " r e d " "red" "red"串,也就是第一种操作,这里面的串的概率和贡献会如何变化呢?
对于上述的一个状态 p i X i p_iX_i piXi,加上一个 " r e d " "red" "red"串之后贡献 X i X_i Xi变为 X i + 1 X_i+1 Xi+1,概率 P i P_i Pi变为 P i 3 \frac{P_i}{3} 3Pi所以这样一种转移让
d p i + 1 , 0 , 0 + = ∑ i = 1 p i 3 ( X i + 1 ) = ∑ i = 1 p i X i 3 + ∑ i = 1 p i 3 dp_{i+1,0,0}+=\sum_{i=1}\frac{p_i} {3} (X_i+1)=\sum_{i=1}\frac{p_iX_i} {3}+\sum_{i=1}\frac{p_i} {3} dpi+1,0,0+=i=13pi(Xi+1)=i=13piXi+i=13pi
所以我们再记录一个 p i , 0 / 1 , 0 / 1 p_{i,0/1,0/1} pi,0/1,0/1表示经过 i i i次操作之后开头为 r e d / e d r red/edr red/edr,结尾为 r e d / e d r red/edr red/edr的串的概率,即可转移。
第二种操作和第三种操作同理可以得到:
对于四种情况各自分类讨论即可。但值得注意的是空串不在我们的考虑范围内,得提出来单独计算。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int mod=1e9+7;
ll poww(ll a,ll b){
    ll t=1;
    while(b){
        if(b&1)t=t*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return t;
}
void add(int &a,int b){
    a+=b;
    if(a>=mod)a-=mod;
}
void del(int &a,int b){
    a-=b;
    if(a<0)a+=mod;
}
const int M=2e5+50;
int dp[M][2][2];
int P[M][2][2];

int main()
{
    int k;
    scanf("%d",&k);
    //P[0][0][0]=1;
    int inv3=poww(3,mod-2);

    int P0=1;
    for(int i=0;i<k;i++){
        //printf("%d %d %d %d\n",P[i][0][0],P[i][0][1],P[i][1][0],P[i][1][1]);

        {
            add(dp[i+1][0][0],1ll*P0*inv3%mod);
            add(P[i+1][0][0],1ll*P0*inv3%mod);

            if(i>=1){
                add(dp[i+1][1][0],1ll*inv3*P0%mod);
                add(P[i+1][1][0],1ll*P0*inv3%mod);

                add(dp[i+1][1][1],1ll*inv3*P0%mod);
                add(P[i+1][1][1],1ll*P0*inv3%mod);

                add(dp[i+1][1][1],1ll*9*inv3%mod*P0%mod);
                add(P[i+1][1][1],1ll*P0*inv3%mod);
            }

            P0=1ll*P0*inv3%mod;
        }



        // red...red
        add(dp[i+1][0][0],((1ll*dp[i][0][0]*inv3%mod)+1ll*P[i][0][0]*inv3%mod)%mod);
        add(P[i+1][0][0],1ll*P[i][0][0]*inv3%mod);

        add(dp[i+1][0][1],1ll*dp[i][0][0]%mod*inv3%mod);
        add(P[i+1][0][1],1ll*P[i][0][0]*inv3%mod);

        add(dp[i+1][0][0],10ll*dp[i][0][0]%mod*inv3%mod);
        add(P[i+1][0][0],1ll*P[i][0][0]*inv3%mod);



        // red..edr dp[0][1]

        add(dp[i+1][0][0],((1ll*dp[i][0][1]*inv3%mod)+1ll*P[i][0][1]*inv3%mod)%mod);
        add(P[i+1][0][0],1ll*P[i][0][1]*inv3%mod);


        add(dp[i+1][0][1],((1ll*dp[i][0][1]*inv3%mod)+1ll*P[i][0][1]*inv3%mod)%mod);
        add(P[i+1][0][1],1ll*P[i][0][1]*inv3%mod);

        add(dp[i+1][0][1],(1ll*(10ll*dp[i][0][1])%mod*inv3%mod));
        add(P[i+1][0][1],1ll*P[i][0][1]*inv3%mod);


        // edr red dp[1][0]

        add(dp[i+1][1][0],((1ll*dp[i][1][0]*inv3%mod)+1ll*P[i][1][0]*inv3%mod)%mod);
        add(P[i+1][1][0],1ll*P[i][1][0]*inv3%mod);

        add(dp[i+1][1][1],1ll*(dp[i][1][0])*inv3%mod);
        add(P[i+1][1][1],1ll*P[i][1][0]*inv3%mod);

        add(dp[i+1][1][0],1ll*(10ll*dp[i][1][0])%mod*inv3%mod);
        add(P[i+1][1][0],1ll*P[i][1][0]*inv3%mod);



        // edr edr dp[1][1]
        add(dp[i+1][1][0],((1ll*dp[i][1][1]*inv3%mod)+1ll*P[i][1][1]*inv3%mod)%mod);
        add(P[i+1][1][0],1ll*P[i][1][1]*inv3%mod);

        add(dp[i+1][1][1],((1ll*dp[i][1][1]*inv3%mod)+1ll*P[i][1][1]*inv3%mod)%mod);
        add(P[i+1][1][1],1ll*P[i][1][1]*inv3%mod);

        add(dp[i+1][1][1],((10ll*dp[i][1][1]%mod*inv3%mod)+9ll*P[i][1][1]%mod*inv3%mod)%mod);
        add(P[i+1][1][1],1ll*P[i][1][1]*inv3%mod);


    }
    int ans=0;
    add(ans,dp[k][0][0]);
    add(ans,dp[k][0][1]);
    add(ans,dp[k][1][0]);
    add(ans,dp[k][1][1]);
    printf("%d",ans);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值