Codeforces Round #362 (Div. 2)D. Puzzles

题意:给你三个杯子,然后把要猜的东西放在中间,然后随意把左右的杯子拿来交换,做n次,然后最后猜的是中间,问你中的概率?这个n很大,他给你k个数,a1……ak,这k个数乘起来表示n。

思路

因为这是一个概率问题,所以先按照状态转移的思想来思考。如果将初始状态定义为  (1,2,3)  ,那么状态空间将只有  6  个元素——  (1,2,3)(1,3,2)(2,1,3)(2,3,1)(3,1,2)(3,2,1)  。但是将状态转移图画好后又会发现没有什么我们需要的线索。那么换一种状态定义方式呢?假设状态  i  为  i  次交换后的状态,令  d[i]  为  i  次交换后初始状态下的中间的杯子(我们可以暂时称之为第  2  个杯子)依然在中间的概率。我们试图寻找  d[i]  与  d[i1]  的关系。不难发现,当状态为  i1  时第  2  个杯子在中间的话,到了状态为  i  的时候第  2  个杯子就不可能在中间了。于是有如下关系

d[i]=1d[i1]2

因为要得到最最简分数形式的概率,因此光得到递推公式是不够的,我们要求一个能直接计算出结果的封闭形式。于是用待定系数法可以得到一个等比数列的递推公式

d[i]13=12(d[i1]13)

解这个递推公式得

d[n]=(1)n+2n13×2n1

凑巧的是, (1)n+2n1  正好是  3  的倍数(与  2  的幂的相邻的两个数中一定有一个是  3  的倍数)而且 (1)n+2n1 除以  3  一定能得到奇数,这样就能与上式分母的偶数互质了。所以有

p=(1)n+2n13

q=2n1

题目就得解了。另外要注意的是,对分数取  mod  的时候要对分母计算模逆元,也就是要算出  3  的模逆元。计算  2n1  的时候可以用快速幂算法来算。

最后,偶然发现像P这样的数被称为  Jacobsthalnumbers  (维基百科)。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll mod = 1e9 + 7;
bool one = true;
int k, odd = 1;
ll a, p, q = 2;

// 快速幂算法
ll modPow(ll a, ll n, ll mod) {
    ll ans = 1;
    for(; n > 0; n >>= 1) {
        if(n & 1) {
            ans = (ans * a) % mod;
        }
        a = (a * a) % mod;
    }
    return ans;
}

// 求模逆元
ll modInv(ll a, ll mod) {
    return modPow(a, mod - 2, mod);
}

int main() {
    scanf("%d", &k);
    for(int i = 0; i < k; i++) {
        scanf("%I64d", &a);
        odd &= (a & 1);
        q = modPow(q, a, mod);
        if(a > 1) {
            one = false;
        }
    }
    q = (q * modInv(2, mod)) % mod;
    if(one == true) {
        p = 0;
    }
    else {
        p = q;
        p += (odd ? -1 : 1);
        p = (p * modInv(3, mod)) % mod;
    }
    printf("%I64d/%I64d\n", p, q);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值