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;
}