【期望+数学推导】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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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;
}

 

你可能感兴趣的:(数学)