CodeForces 868G. El Toll Caves

这篇博客介绍了一个关于寻找宝藏的数学问题,其中N个洞穴中有一个藏有宝藏。每天可派遣K个机器人探索洞穴,找到宝藏的概率为50%。博主通过递归算法,转换问题并求解了找到宝藏的期望天数。讨论了如何将原问题转化为n=3, k=2的子问题,并给出了具体的迭代公式来计算答案。" 128049760,5750663,"华为机试解题:分苹果算法实现(Java, JS, Python, C)
摘要由CSDN通过智能技术生成

链接:

link

题意:

N 个洞穴,其中一个有宝藏,每天可以派K个机器人去一些洞穴找宝藏,如果机器人所在洞穴里有宝藏就有 50% 的概率找到宝藏,求找到宝藏的期望天数。

题解:

先举个 n=8,k=3 的例子。

Ei 表示发现宝藏在 i 的期望天数,那么有E3=E0+1,E4=E1+1...

同时有 E0=E52+1 (去掉在第一次访问 1 时就找到宝藏)。

注意到E0+E3+E6=3E0+3,E1+E4+E7=3E1+3,E2+E5=2E2+1

那么问题可以变成 n=3,k=2 的子问题。

考虑一般情况,记 Ei+k=A(Ei),Ei+kn=B(Ei) ,我们要求的就是

Ans=k1j=0S1(Ej)+n1j=kS2(Ej)

化为子问题后, Ans=k1j=0S1(Ej)+k1j=kS2(Ej)

Ai 表示 A 迭代i次后的结果,例如 x+2 迭代3次后是 =x+6 ,那么有

S1=S1+nki=1S2(Ai)

S2=S1+nk1i=1S2(Ai)

那么我们只需要求 A B 就可以递归下去了。

注意到 Ej+kk=B(Ank(Ej))

Ej+kk=Ank(B1(Ej)) ,这个就是 B

同理可以推出 A=Ank1(B1(Ej))

然后就做完了。

代码:

#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;

typedef long long LL;
typedef pair <int, int> pii;

inline int Read()
{
    int x = 0, f = 1, c = getchar();
    for (; !isdigit(c); c = getchar())
        if (c == '-')
            f = -1;
    for (;  isdigit(c); c = getchar())
        x = x * 10 + c - '0';
    return x * f;
}

const int mod = 1e9 + 7;

inline int Qow(int x, int y)
{
    int r = 1;
    for (; y; y >>= 1, x = 1LL * x * x % mod)
        if (y & 1)
            r = 1LL * r * x % mod;
    return r;
}

inline int F(int a, int q)
{
    if (q <= 0)
        return 0;
    if (a == 1)
        return q;
    return 1LL * (Qow(a, q) - 1) * Qow(a - 1, mod - 2) % mod;
}

inline int G(int a, int q)
{
    if (q <= 0)
        return 0;
    if (a == 1)
        return (1LL * q * (q + 1) >> 1) % mod;
    int v = Qow(a - 1, mod - 2);
    return 1LL * (1LL * (Qow(a, q) - 1) * a % mod * v % mod + mod - q) * v % mod;
}

inline int Solve(int n, int k, int A_1, int A_0, int B_1, int B_0, int S1_1, int S2_1, int S_0)
{
    if (n == 1)
        return (1LL * S1_1 * B_0 % mod * Qow(mod + 1 - B_1, mod - 2) + S_0) % mod;

    int q = (n - 1) / k, r = n - q * k, A__1, A__0, B__1, B__0, S1__1, S2__1, S__0, x, y;

    x = 1LL * B_1 * Qow(A_1, q - 1) % mod, y = (1LL * A_0 * B_1 % mod * F(A_1, q - 1) % mod + B_0) % mod;
    A__1 = Qow(x, mod - 2), A__0 = (mod - 1LL * y * A__1 % mod) % mod;

    x = 1LL * B_1 * Qow(A_1, q) % mod, y = (1LL * A_0 * B_1 % mod * F(A_1, q) % mod + B_0) % mod;
    B__1 = Qow(x, mod - 2), B__0 = (mod - 1LL * y * B__1 % mod) % mod;

    S1__1 = (1LL * S2_1 * A_1 % mod * F(A_1, q) + S1_1) % mod;
    S2__1 = (1LL * S2_1 * A_1 % mod * F(A_1, q - 1) + S1_1) % mod;

    S__0 = (1LL * S2_1 * A_0 % mod * (1LL * r * F(A_1, q) % mod + 1LL * k * G(A_1, q - 1) % mod) + S_0) % mod;

    return Solve(k, r, A__1, A__0, B__1, B__0, S1__1, S2__1, S__0);
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    for (int T = Read(); T; T --)
    {
        int n = Read(), k = Read(), d = __gcd(n, k);
        n /= d, k /= d;
        printf("%d\n", 1LL * Solve(n, k, 1, 1, mod + 1 >> 1, 1, 1, 1, 0) * Qow(n, mod - 2) % mod);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值