CF908D New Year and Arbitrary Arrangement 题解
Description
给定 ,有一初始为空的序列。
每次有 的概率往序列后面加一个 a
。
每次有 的概率往序列后面加一个 b
。
当出现大于等于 个形如 ab
的子序列(a
和 b
不一定相邻)时停止。
求序列最终的 ab
子序列期望数。
Solution
为了更加简洁,文中的 指题意中的 , 指 。
看到求期望,可以先试着写写 dp
。
设 表示有 个 a
、 个 b
、 个 ab
时的期望。
发现当前有 个 a
时,再加一个 b
会产生 个 ab
,与之前 b
的数量无关,所以省去一维 dp
。
设 表示有 个 a
、 个 ab
时的期望。
由于我们只知道终止状态,所以倒推会更好写且容易理解。
有 的概率加 a
变为 ,有 的概率加 b
变为 ,得出转移方程:
答案即为 。
接下来是本题最难部分,求满足终止条件的 值。
终止条件为 ,此时只要再加一个 b
就可以终止。
然而在加 b
前可能有若干个 a
,无法确定 a
的数量,所以要开始推式子。
Sol1
这种方法用了等比数列的思想。
为 a
的出现次数,a
每多在 b
前出现一次,最后的 ab
就会多一个,所以总共加了 个 ab
。
继续推:
设 。
变为 的原因是 变为 开始。
设 。
Sol2
对于 和 ():
由于后面的 b
终止前,新的 a
产生的多余 ab
期望数都是一样的。
所以两期望的区别只有当前 a
相差 造成的期望 。
即 。
Code
#include<bits/stdc++.h>
using namespace std;
#define mo 1000000007
#define int long long
int k,a,b,pa,pb;
int f[1010][1010];
int po(int x,int y){
int z=1;
while(y){
if(y%2) z*=x;
x*=x;
x%=mo,z%=mo;
y/=2;
}
return z;
}
signed main(){
cin>>k>>a>>b;
pa=a*po(a+b,mo-2)%mo;
pb=b*po(a+b,mo-2)%mo;
for(int i=k;i>=1;i--){
for(int j=k;j>=0;j--){
if(i+j>=k){
f[i][j]=pa*po(pb,mo-2)%mo+i+j;
f[i][j]%=mo;
}else{
f[i][j]=f[i+1][j]*pa%mo+f[i][j+i]*pb%mo;
f[i][j]%=mo;
}
}
}
cout<<f[1][0];
return 0;
}
本文作者:larryyu_blog
本文链接:https://www.cnblogs.com/larryyu/p/18351911
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步