[ABC008C] コイン 题解

[ABC008C] コイン

一道有趣的期望题。

解法

题中给出 n n n 枚硬币,每枚硬币上都有一个正整数,记作 a i a_i ai。下面为了方便叙述,我们将 n n n 个硬币进行标号,依次为 1 1 1 n n n

现在要将这 n n n 枚硬币进行全排列,共有 n ! n! n! 种排列方法,求出全部翻转后最终正面朝上(初始状态是全部正面朝上)的硬币数量的期望值(输出浮点数)。翻转规则如下:

  • 从最左端开始向右逐个扫过。

  • 当扫到第 i i i 个硬币时,我们将第 i i i 个硬币右侧且硬币上的数字是 a i a_i ai 倍数的硬币进行一次翻转。

注意:本题要注意整数和浮点数间的转换。

部分分解法

对于 1 ≤ n ≤ 8 1 \le n \le 8 1n8 的情况,我们可以全排列出所有情况,对于每一种情况暴力翻转,求出每种情况硬币正面朝上的数量,从而算出所有情况硬币正面朝上的数量的总和,除以 n ! n! n! 浮点数输出期望即可。

满分解法

考虑到有一个点的数据范围是 1 ≤ n ≤ 100 1 \le n \le 100 1n100,这种暴力的做法是不能得到满分的。考虑到我们正在对每种排列情况进行计数,我们可以换一个计数方式,即考虑每个硬币在所有情况中正面朝上的概率的总和。

观察样例我们可以得到:对于编号为 i i i 的硬币,能使之翻转的硬币只能是 a i a_i ai 的约数所在的硬币。所以如果对于 a j ∤ a i a_j \nmid a_i ajai,在任意排列中无论编号为 j j j 的硬币在编号为 i i i 的硬币的任何方向,都不会影响编号为 i i i 的硬币的翻转情况。所以我们在计数编号为 i i i 的硬币时可以忽略这些不是该硬币约数的硬币。现在即求对于编号为 i i i 的硬币和它的 x i x_i xi 个约数,在这 x i + 1 x_i +1 xi+1 个数的全排列中有多少种情况编号为 i i i 的硬币在这列数中排在第奇数位(即该数前面有偶数个约数)的概率。对于编号为 i i i 的硬币,计算公式为:$\dfrac{ x_i! \times \lfloor x_i / 2 + 1 \rfloor }{ (x_i + 1)! } = \dfrac{ \lfloor x_i / 2 + 1 \rfloor }{ x_i + 1 } $,解释如图:

代码

#include<bits/stdc++.h>
using namespace std;
int n,a[110];
double ans;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1,cnt=0;i<=n;i++,cnt=0)
	{
		for(int j=1;j<=n;j++) if(a[i]%a[j]==0) cnt++;
		cnt--;//把自己排除
		ans+=(cnt/2+1)*1.0/(cnt+1);
	}
	cout<<fixed<<setprecision(6)<<ans<<endl;//注意,因为这道题是早期 AT 的题,最后一定要多输出一个空格
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值