hdu 6747 rotate 【数学期望】

http://acm.hdu.edu.cn/showproblem.php?pid=6747

Problem Description

我们有一个圈,从内到外一共被分成了 n 个环,中间是空的。

我们把从外到内第 i 层环平分成 a[i] 份,其中 a[i] 是偶数,我们把这 a[i] 份黑白染色,第奇数个染成黑色,第偶数个染成白色。

现在我们旋转每一层,每一层都会等概率随机到一个中止位置。

问黑色的联通块数目的期望。两块黑色的区域有交点即算联通。层之间的旋转是相互独立的。

Input

第一行一个正整数 test(1≤test≤10) 表示数据组数。

对于每组数据,第一行一个正整数 n(1≤n≤10)。

接下来一行 n 个正整数 a[i](2≤a[i]≤1000),a[i] 为偶数,另外保证 a 序列不降。

Output

对于每组数据,一行一个数表示答案,由于答案 A/B 中的 AB 可能很大,请输出 A/Bmod109+7,假设 A/B 为最简分数,A/Bmod109+7=A∗B−1mod109+7,B−1 为满足 B−1∗Bmod109+7=1 的整数。

分析:

首先,我们已知在相邻两层,外层的黑块数是大于等于内层的黑块数的,这样就可以得到外层某一黑块数与内层有两个及以上的黑块相连的概率为0(几何概型,对于只在某几个角度上与内层有两个黑块相连的概率视为0)。

所以对每一个连通块,从内往外看都是一个树形结构。内层黑块为父节点,外层黑块为子节点。内层黑块可以连接外层多个黑块,外层每个黑块向内最多只连接一个黑块。

所以整个圈就构成了一个森林。易得:联通块的个数 = 点数 - 边数。取期望,E(联通块的个数) = E(点数) −E(边数)。

因为:树的性质是节点数-边数=1,所以森林里树的棵数(即连通块的个数)就是总的节点数-总的边数。

边数怎么求呢?我们考虑相邻的两层。为了方便,设内层块数为 2a,外层的块数为 2b 。可知内层每个黑块的圆心角为 Pi/a ,外层每个黑块的圆心角为 Pi/b 。可知外层任意某一个黑块与内层任意某一个黑块相连的概率A为 ( (Pi/a) + (Pi/b) ) / (2*Pi)。所以外层任意某一个黑块与内层黑块相连的概率B为A*a。则外层任意某一个黑块与内层黑块相连的个数的期望为B*1 (表示相连的个数为一个)。(Pi=3.14159265...)

那么外层黑块与内层黑块相连的个数的期望是多少呢?B*1*b。证明:我们设随机变量 x[i] 表示:若外层的第 i 个黑块与内层的某个黑块相连,则 x[i]=1,否则 x[i]=0。则期望E=E( x[1] + x[2] + ... + x[b] )=E(x[1]) + E(x[2]) + ... + E(x[b])。因为每一块的大小都是一样的,所以P(x[1])=P(x[2])=...=P(x[b])。又因为E(x[i])=P(x[i])*1。所以E(x[1])=E(x[2])=...=E(x[b])。所以E=E(x[i])*b。(1<=i<=b)。前面已经证明外层任意某一个黑块与内层黑块相连的个数的期望为B*1。所以E=B*1*b=A*a*b*1=(a+b)/2。

最后得E(联通块的个数) = E(点数) −E(边数) = (a[1]+a[n])/4。

因为有除法,需要用到逆元。这里只给结论,有关逆元的详细内容请自行查找。若p为质数,(a / b) %p = a*pow(b, p-2) %p

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const ll inv4=250000002LL;//25e7+2 / 2.5e8+2
const ll inv2=500000004LL;//5e8+4
int qp(ll a, ll b)//快速幂取模 
{
	ll ans=1;
	while(b)
	{
		if(b&1) ans=ans*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return ans;
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n,ans;
		scanf("%d%d",&n,&ans);
		if(n==1)//特判n=1的时候,开始没注意n可以取1导致自己wa了一发 
		{
			printf("%d\n", ans/2);
			continue;
		}
		for(int i=2;i<n;i++) scanf("%*d");//因为第一个数已经放到ans里了,现在我们就只需要得到最后一个数就可以了 
		scanf("%d",&n);
		ans = ( ( (ll)ans+n ) * inv4) % mod;
		printf("%d\n", ans);
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值