【cf908D】New Year and Arbitrary Arrangement

12 篇文章 0 订阅

1.题目链接。题目大意,给定k,a,b.现在构造一个字符串,每个位置有两种选择,a/(a+b)概率会选择'a',b/(a+b)会选择'b'.当ab这个子序列出现的次数大于等于k次之后就停止构造,问ab这个子序列出现的期望次数。

2.还是比较有意思的一道题目,还是求期望,那么一般还是倒着dp.dp[i][j]表示出现了i个a,j个ab子序列的期望。倒着考虑时,转移式很好推出来。
                   dp[i][j]=dp[i][j]+pa/(pa+pb)*dp[i+1][j]+pb/(pa+pb)*dp[i][i+j].

解释一下这个dp式子,在倒着考虑时,如果当前为是a,那么等于i+1个a并且j个ab转移过来,如果当前字符是b,那么就对答案有贡献了,前面的所有的a都会和这个b组合,产生i个ab.那么就会从i转移过来。这是一个人人为我的dp。最后考虑到起点就是答案。但是有两种特例:

(1)bbbbbbbbabbbbb这种,前边有很多b,因为a不存在,所以b没有。这个时候dp[1][0]=dp[0][0]就是答案。

(2)aaaaaaaaaa.....b.有无限多个a,这时一旦出现一个b,就会产生很大的贡献,立刻就满足条件了,但是i+k这个时候大于k,这个状态就没办法再从前边推出来,这个可以手算一下,是一个差比数列(等差数列和等比梳理的复合)。计算一下可以得到:

               dp[i][j]=i+j+pa/pb.

然后这个题就做完了。

#include<bits/stdc++.h>
#define ll long long
#define mod 1000000007
ll k, pa, pb, dp[1100][1100];
ll qpow(ll a, ll b) {
	ll res = 1;
	while (b) {
		if (b & 1)res = res * a%mod;
		a=a*a%mod;
		b >>= 1;
	}
	return res;
}
int main() {
	scanf("%lld%lld%lld", &k, &pa, &pb);
	ll ca = pa, cb = pb;
	ll invab = pa * qpow(cb, mod - 2) % mod;
	pa = pa * qpow(ca + cb, mod - 2)%mod;
	pb = pb * qpow(ca + cb, mod - 2)%mod;
	for (int i = k; ~i; --i)
		for (int j = k; ~j; --j)
			if (i + j >= k) dp[i][j] = (i + j + invab) % mod;
			else dp[i][j] = pa * dp[i + 1][j] % mod + pb * dp[i][i + j] % mod, dp[i][j] %= mod;
	printf("%lld", dp[1][0]);
	return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值