Live2D

Solution -「CF 908D」New Year&Arbitrary Arrangement

Description

  Link.

  给定 n,pa,pb,初始有一个空串,每次操作有 papa+pb 的概率在其后添加字符 'a'pbpa+pb 的概率添加字符 'b',当子序列 {'a','b'} 的个数不小于 n 时,结束操作。求子序列的期望个数,对 109+7 取模。

  n1000

Solution

  显然状态,f(i,j) 表示有 i'a'j{'a','b'} 的期望串长。为方便转移,令 pa 为出现 'a' 的概率,pb 同理。对于一般情况的转移:

f(i,j)=paf(i+1,j)+pbf(i,i+j)

  当 i+jn,若再出现一个 'b',操作必然停止。那么:

f(i,j)=pbk=0+pak(i+j+k)paf(i,j)=pbk=1+pak(i+j+k1)(1pa)f(i,j)=pb(i+j+k=1+pak)pbf(i,j)=pb(i+j+papb)f(i,j)=i+j+papb

  而初始状态有:

f(0,0)=paf(1,0)+pbf(0,0)=pa1pbf(1,0)=f(1,0)

  DP 就好了 w。

Code

#include <cstdio>
#include <cstring>

typedef long long LL;

const int MAXN = 1000, MOD = 1e9 + 7;
int n, pa, pb, div, f[MAXN + 5][MAXN + 5];

inline int add ( int a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; }
inline int mul ( LL a, const int b ) { return ( a *= b ) < MOD ? a : a % MOD; }
inline int sub ( int a, const int b ) { return ( a -= b ) < 0 ? a : a + MOD; }

inline int qkpow ( int a, int b ) {
	int ret = 1;
	for ( ; b; a = mul ( a, a ), b >>= 1 ) ret = mul ( ret, b & 1 ? a : 1 );
	return ret;
}

inline int solve ( const int a, const int k ) {
	if ( a + k >= n ) return add ( a, add ( k, div ) );
	if ( ~ f[a][k] ) return f[a][k];
	return f[a][k] = add ( mul ( pa, solve ( a + 1, k ) ), mul ( pb, solve ( a, a + k ) ) );
}

int main () {
	int ta, tb;
	scanf ( "%d %d %d", &n, &ta, &tb );
	memset ( f, -1, sizeof f );
	pa = mul ( ta, qkpow ( add ( ta, tb ), MOD - 2 ) );
	pb = mul ( tb, qkpow ( add ( ta, tb ), MOD - 2 ) );
	div = mul ( pa, qkpow ( pb, MOD - 2 ) );
	printf ( "%d\n", solve ( 1, 0 ) );
	return 0;
}
posted @   Rainybunny  阅读(116)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示