CF1139D Steps to One 题解

Description

给一个数列,每次随机选一个 \(1\)\(m\) 之间的数加在数列末尾,数列中所有数的 \(\gcd=1\) 时停止,求期望长度。

\(m\le10^5\)

Sol

\(E(x)\) 表示选择 \([1,x]\) 内的数,\(P(x)\) 事件 \(x\) 的概率,那么我们有:

\[E(x)=\sum_{i\ge1}P(len=i)\times i \]

将后面的 \(i\) 转化为 \(\sum\) 可得

\[E(x)=\sum_{i\ge1}\sum_{j=1}^iP(len=i) \]

交换求和符号

\[E(x)=\sum_{j\ge1}\sum_{i\ge j}P(len=i) \]

\[E(x)=\sum_{i\ge1}P(len\ge i) \]

因为 \(\sum_{i\ge1}P(len=i)=1\),所以

\[E(x)=1+\sum_{i\ge1}P(len>i) \]

由于 \(P(len>i)\) 的意义就是取了 \(i\) 个数后没有结束的概率,那么我们暴力枚举每一种情况,有

\[P(len>i)=1-\frac{\sum_{a_1=1}^m\sum_{a_2=1}^m...\sum_{a_i=1}^m[\gcd_{k=1}^i a_k=1]}{m^i} \]

对上式进行莫反,得

\[P(len>i)=1-\frac{\sum_{a_1=1}^m\sum_{a_2=1}^m...\sum_{a_i=1}^m\sum_{d|\gcd_{k=1}^i a_k}\mu(d)}{m^i} \]

枚举 \(d\),得

\[P(len>i)=1-\frac{\sum_{d=1}^m\sum_{a_1=1}^m[d|a_1]\sum_{a_2=1}^m[d|a_2]...\sum_{a_i=1}^m[d|a_i]}{m^i} \]

\[P(len>i)=1-\frac{\sum_{d=1}^m\mu(d)(\lfloor\frac{m}{d}\rfloor)^i}{m^i} \]

由于 \(\frac{\mu(1)(\lfloor\frac{m}{1}\rfloor)^i}{m^i}=1\),与前面的 \(1\) 抵消,所以

\[P(len>i)=-\frac{\sum_{d=2}^m\mu(d)(\lfloor\frac{m}{d}\rfloor)^i}{m^i} \]

代入回原式,得

\[E(x)=1-\sum_{i\ge1}\frac{\sum_{d=2}^m\mu(d)(\lfloor\frac{m}{d}\rfloor)^i}{m^i} \]

\[E(x)=1-\sum_{i\ge1}\frac{1}{m^i}\sum_{d=2}^m\mu(d)(\lfloor\frac{m}{d}\rfloor)^i \]

交换求和符号

\[E(x)=1-\sum_{d=2}^m\mu(d)\sum_{i\ge1}(\frac{\lfloor\frac{m}{d}\rfloor}{m})^i \]

利用等比数列求和公式:

\[E(x)=1-\sum_{d=2}^m\mu(d)\frac{\lfloor\frac{m}{d}\rfloor}{m-\lfloor\frac{m}{d}\rfloor} \]

然后预处理 \(\mu\) 就可以 \(O(m)\) 做了。

Code

#include<bits/stdc++.h>
#define int long long
#define Mod 1000000007
using namespace std;
int Read() {
    int x = 0, f = 1; char ch = getchar();
    while(!isdigit(ch)) {if(ch == '-')  f = -1; ch = getchar();}
    while(isdigit(ch)) {x = (x << 3) + (x << 1) + ch - '0'; ch = getchar();}
    return x * f;
}
int n, cnt, prime[100005], isp[100005], mu[100005], inv[100005];
void prework() {
    for(int i = 2; i <= n; i++) {
        if(!isp[i])  prime[++cnt] = i, mu[i] = -1;
        for(int j = 1; j <= cnt && i * prime[j] <= n; j++) {
            isp[i * prime[j]] = 1; mu[i * prime[j]] = -mu[i];
            if(i % prime[j] == 0)  {mu[i * prime[j]] = 0; break;}
        }
    }
}
signed main() {
    n = Read();
    inv[1] = 1;
    for(int i = 2; i <= n; i++)
        inv[i] = (Mod - Mod / i) * inv[Mod % i] % Mod;
    prework();
    int res = 1;
    for(int i = 2; i <= n; i++) {
        res = res - mu[i] * (n / i) % Mod * inv[n - n / i] % Mod;
        res = (res + Mod) % Mod;
    }
    cout << res << endl;
    return 0;
}
posted @ 2020-10-16 07:38  verjun  阅读(70)  评论(0编辑  收藏  举报