Live2D

Solution -「LOCAL」舟游

Description

  n 中卡牌,每种三张。对于一次 m 连抽,前 m1 次抽到第 i 种的概率是 pi,第 m 次抽到第 i 种的概率是 qi。若抽到第 i 种,会等概率地得到三张卡牌中的一张。求得到所有 3n 张卡的期望 m 连抽次数。对 2000000011 取模。

  n6m64

Solution

  目睹 Tiw 踩标算,%%%

Case 1

  长得就像状压期望 DP。令 f(S,i) 表示抽到的卡牌集合为 S(同种卡牌显然无序,用两个 bit 记录一种卡牌拥有的张数即可)。发现转移会有一个 f(S,1)f(S,2)f(S,m)f(S,1) 的大小为 m 的简单环。手动消元解出来就好。

  考 场 上 写 自 闭 了。

Case 2

  长得就像 Min-Max 反演——Tiw。Min-Max 反演在期望意义下的式子长成:

E(maxξS{ξ})=TST(1)|T|1E(minξT{ξ})

  其中 S 是随机变量集合。对于本题,我们相当于要求每张卡被抽到时间的最大值的期望,可以用上式反演成求每张卡被抽到时间的最小值的期望。为方便推式子,令 pq 的意义为抽到某一张卡的概率。对于某个具体的卡牌集合,就要求至少抽中 T 中一张卡牌的期望时间。那么:

E(minξT{ξ})=11(1cTpc)m1(1cTqc)

  枚举集合 T,就做完了。(

  复杂度 O(4nlog2000000011)

Code

  Case 2.

/* Clearink */

#include <cstdio>

typedef long long LL;

const int MAXN = 9, MAXM = 64, MAXS = 1 << 18, MOD = 2000000011;
int n, m, ans, p[MAXN + 5], q[MAXN + 5];

inline int add ( LL a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; }
inline int sub ( LL a, const int b ) { return ( a -= b ) < 0 ? a + MOD : a; }
inline int mul ( LL a, const int b ) { return ( a *= b ) < MOD ? 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 void solve ( const int id, const bool s, const int sump, const int sumq, const int ways ) {
	if ( id == n + 1 ) {
		int val = mul ( ways, qkpow (
			sub ( 1, mul ( qkpow ( sub ( 1, sump ), m - 1 ), sub ( 1, sumq ) ) ), MOD - 2 ) );
		ans = ( s ? add : sub )( ans, val );
		return ;
	}
	solve ( id + 1, s, sump, sumq, ways );
	solve ( id + 1, !s, add ( sump, p[id] ), add ( sumq, q[id] ), mul ( ways, 3 ) );
	solve ( id + 1, s, add ( sump, mul ( p[id], 2 ) ), add ( sumq, mul ( q[id], 2 ) ), mul ( ways, 3 ) );
	solve ( id + 1, !s, add ( sump, mul ( p[id], 3 ) ), add ( sumq, mul ( q[id], 3 ) ), ways );
}

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