【期望+数学推导】hdu6747 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 的整数。

 

 

【分析】

观察得到的性质:黑色的联通块构成了一个森林。

证明:因为序列a单调不降,所以从外而内每一圈被分成的被平分的份数越来越多,即越向内分的越细,外圈的一个黑块可以向内连接多个黑块,内圈的方块向外最多连接一个黑块,是一个树形结构,外圈为父亲节点,内圈为子节点。

对于森林,联通块的个数 = 点数 - 边数,取期望,E(联通块的个数) = E(点数) −E(边数)

考虑第i圈,第i圈共有a[i] / 2个黑点,对E(点数)的贡献为ai / 2,

计算它向第i + 1圈(向内一圈)连边的边数期望E(i),则E(总边数) = E[1] + E[2] + ... + E[n - 1]

第i + 1圈共有(a[i + 1] / 2)个黑点,设随机变量X[i],若第i + 1圈第i个黑点与第i圈的某个黑点联通(即有1条连边),则X[i] = 1,若无则X[i] = 0,

因此E[i] = E( X[1] + X[2] + ... + X[ a[i + 1] / 2 ] ),

根据期望的线性性:

E[i] = E( X[1] )  + E( X[2] ) + ... + E( X[ a[i + 1] / 2 ] ) )

由于旋转对称性

E( X[1] )  = E( X[2] ) = ... = E( X[ a[i + 1] / 2 ] ) )

故E[i] = E( X[1] )  * a[i + 1] / 2 

只需计算内圈的一个黑块与外圈连边的期望

内圈的一个黑块(图中红块)的一边在蓝色夹角内活动,蓝色的夹角为2 * Pi / (1 / a[i] * 2),有连边的临界情况即为图中的两个红色部分,所占的角度范围为2*PI * (1 / a[i] + 1 / a[i + 1]),因此有连边的概率为 P(X1)=(2*PI * (1 / a[i] + 1 / a[i + 1])/ (2 * Pi / (1 / a[i] * 2)),则期望E(X1)= P(X1) * 1(代表一条边),所以E[i] = E( X[1] )  * a[i + 1] / 2 = ( a[i] +  a[i + 1]  )/ 4

 

最后答案即为 (a[1] + a[n]) / 4

#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
#define f(i,l,r) for(int i=(l);i<=(r);i++)
#define ff(i,r,l) for(int i=(r);i>=(l);i--)
#define fe(i,u) for(int i=h[u];~i;i=e[i].nxt)
#define ll long long
using namespace std;
const int MAXN = 1e6 + 5;
const int MAXM = 1200010;
const int MOD = 1e9 + 7;
const int Inv2 = 500000004;
int n;
int T;
const int Inv4 = 250000002;
ll Pow(ll a, ll b, int MOD)
{
    ll res = 1;
    while(b){
        if(b & 1) res = res * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return res;
}
int main()
{
//    freopen("data.in", "r", stdin);
//    freopen("test.out", "w", stdout);
    cin >> T;
    while(T --){
        cin >> n;
        ll a, b;
        cin >> a;
        if(n == 1){
            cout << a / 2 << endl;
            continue;
        }
        f(i, 2, n){
            cin >> b;
        }
        ll ans = (a + b) / 2;
        cout << ans * Inv2 % MOD << endl;

    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值