ACM-ICPC 2017 Asia Urumqi A.Coins解题报告

ACM-ICPC 2017 Asia Urumqi A.Coins

题目大意

n n n枚硬币反面朝上,有 m m m次操作,每次需要投掷 p p p枚硬币,问你最后正面朝上的硬币个数的期望是多少

解题思路

d p [ i ] [ j ] dp[i][j] dp[i][j]表示第 i i i次投掷有 j j j枚硬币正面朝上的概率, k k k表示第 i i i次投掷 p p p枚硬币后有 k k k枚硬币正面朝上的概率,那么其转移方程即为:
{ d p [ i ] [ j + k ] = ∑ d p [ i − 1 ] [ j ] × C p k × 2 − p     j ≤ n − p d p [ i ] [ j − ( p − ( n − j ) ) + k ] = ∑ d p [ i − 1 ] [ j ] × C p k × 2 − p j > n − p \begin{cases} dp[i][j + k]=\sum dp[i-1][j] \times C_{p}^{k} \times 2^{-p}\qquad \qquad \qquad \qquad \ \ \ j \leq n-p \\ dp[i][j - (p - (n - j)) + k] = \sum dp[i-1][j] \times C_{p}^{k} \times 2^{-p} \qquad j > n - p \\ \end{cases} {dp[i][j+k]=dp[i1][j]×Cpk×2p   jnpdp[i][j(p(nj))+k]=dp[i1][j]×Cpk×2pj>np
其中第一个式子表示当前反面朝上的硬币数目多于 p p p枚,那么我们只要从剩余的 n − j n-j nj枚硬币中选择 p p p枚反面朝上的硬币进行投掷,最后成功将 k k k枚硬币变成正面朝上的概率,第二个式子表示当期反面朝上的硬币数目少于 p p p枚,那么我们就需要选择一些已经正面朝上的硬币进行投掷,其数目为 p − ( n − j ) p-(n-j) p(nj),同样, k k k表示投掷 p p p枚硬币后正面朝上的硬币个数

则有期望 E = ∑ i = 1 n d p [ m ] [ i ] × i E=\sum_{i=1}^{n}dp[m][i] \times i E=i=1ndp[m][i]×i

预处理出 100 100 100以内的 C k p C_{k}^{p} Ckp 2 − p 2^{-p} 2p后根据公式计算即可

注: C C C数组开 l o n g l o n g longlong longlong会爆掉,需要使用 d o u b l e double double类型存储

AC代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 110;
double P[maxn];
double C[maxn][maxn];
double dp[maxn][maxn];
void pre() {
	P[0] = C[0][0] = 1.0;
	for (int i = 1; i < maxn; ++i) {
		C[i][0] = 1;
		for (int j = 1; j <= i; ++j) C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
	}
	for (int i = 1; i < maxn; ++i) P[i] = P[i - 1] / 2.0;
}
int main() {
	pre();
	int T;
	scanf("%d", &T);
	while (T--) {
		int n, m, p;
		scanf("%d%d%d", &n, &m, &p);
		memset(dp, 0, sizeof(dp));
		dp[0][0] = 1;
		for (int i = 1; i <= m; ++i) {
			for (int j = 0; j <= n; ++j) {
				for (int k = 0; k <= p; ++k) {
					if (n - j >= p) dp[i][j + k] += dp[i - 1][j] * C[p][k] *  P[p];
					else dp[i][j - (p - (n - j)) + k] += dp[i - 1][j] * C[p][k] * P[p];
				}
			}
		}
		double res = 0;
		for (int i = 1; i <= n; ++i) res += dp[m][i] * i;
		printf("%.3f\n", res);
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值