CF1139D Step to One
题目描述
你手中有集合 ,然后每一次操作你都会从数集中等概率抽取一个数放到新的序列中,直到新的序列的
的值为
。
求你的期望操作次数
分析
这道题十分的精妙,它集合了数学期望还有莫比乌斯反演,十分考验 的基础能力
数学期望
首先知道, 表示对于事件
的数学期望,
表示事件
的概率
那么有:
这个步骤,就是期望步数(概率 * 步数),显然就是期望公式
其中 表示达到
花费的步数
那么重点就是这个该如何处理了
想要 那么可以理解为长度为
时的
所以可以有如下化简:
莫比乌斯反演
这个和之前的某道题有点像,所以化简过程就不写了,所以就可以得到
这一步也很显然
那么现在就可以带回数学期望的式子里,可以得到:
那么最后数论分块 +。线性筛逆元一下就可以了,时间复杂度 ,但是其实也是可以
做的,毕竟数据范围很小
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int __read()
{
int x(0), t(1);
char o (getchar());
while (o < '0' || o > '9') {
if (o == '-') t = -1;
o = getchar();
}
for (; o >= '0' && o <= '9'; o = getchar()) {
x = (x << 1) + (x << 3) + (o ^ 48);
}
return x * t;
}
int mu[maxn], inv[maxn];
int pr[maxn], cnt, ans(1);
bool vis[maxn];
inline void init(int maxn)
{
mu[1] = inv[1] = 1;
for (int i = 2; i <= maxn; ++i) {
if (!vis[i]) pr[++cnt] = i, mu[i] = - 1;
for (int j = 1; j <= cnt && i * pr[j] <= maxn; ++j) {
vis[i * pr[j]] = 1;
if (i % pr[j]) mu[i * pr[j]] = -mu[i];
else break;
}
}
for (int i = 2; i <= maxn; ++i) {
mu[i] += mu[i - 1];
inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
}
}
int main()
{
int n = __read();
init(n);
for (int l = 2, r; l <= n; l = r + 1) {
r = n / (n / l);
int temp = n / l;
ans = ((ans - 1ll * (mu[r] - mu[l - 1]) % mod * temp % mod * inv[n - temp] % mod) % mod + mod) % mod;
}
printf ("%d\n", ((ans % mod) + mod) % mod);
} 
京公网安备 11010502036488号