cf1139D(概率DP+莫比乌斯函数)

题目链接

https://codeforces.com/contest/1139/problem/D

题意

每定 $m(m\le1e5)$ ,每次从$1\sim m$ 中等概率取一个数,直到所有数的 $gcd$ 等于 $1$ 为止,问取的数的个数的期望

题解

设 $f[i]​$ 为当前 $gcd​$ 为 $i​$ 到结束的期望步数

那么答案为 $\frac{1}{m}\sum_{i=1}^m f[i]$

然后考虑降复杂度,主要将 $n​$ 个数按 $gcd​$ 分类

那么

那么

然后边维护 $f$ 边维护 $g$ 就可以了

当然对于 $d=1$ 的情况需要特判,然而在算出 $f$ 之前,$g$ 里面的 $d[i]$ 是为 $0$ 的,所以直接代入算是可以了,只要最后记得把 $d[i]$ 加回来就可以了。。

复杂度 $O(n\sqrt n)$

如果直接用埃筛先预处理出每个数的因子,那么复杂度可降为 $O(nlogn)$

然而只快了一半(雾)。。




代码

$O(n\sqrt n)​$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/**
*         ┏┓    ┏┓
*         ┏┛┗━━━━━━━┛┗━━━┓
*         ┃       ┃  
*         ┃   ━    ┃
*         ┃ >   < ┃
*         ┃       ┃
*         ┃... ⌒ ...  ┃
*         ┃ ┃
*         ┗━┓ ┏━┛
*          ┃ ┃ Code is far away from bug with the animal protecting          
*          ┃ ┃ 神兽保佑,代码无bug
*          ┃ ┃           
*          ┃ ┃       
*          ┃ ┃
*          ┃ ┃           
*          ┃ ┗━━━┓
*          ┃ ┣┓
*          ┃ ┏┛
*          ┗┓┓┏━━━━━━━━┳┓┏┛
*           ┃┫┫ ┃┫┫
*           ┗┻┛ ┗┻┛
*/

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<set>
#include<bitset>
#include<assert.h>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y)/2
#define NM 200005
#define nm 105
#define pi 3.1415926535897931
using namespace std;
const ll inf=1e9+7;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}








int n,mu[NM],tot,prime[NM];
bool v[NM];
ll d[NM],f[NM],inv,ans;
ll qpow(ll x,ll t){return t?qpow(sqr(x)%inf,t>>1)*(t&1?x:1ll)%inf:1ll;}
void init(){
n=1e5;mu[1]=1;
inc(i,2,n){
if(!v[i])prime[++tot]=i,mu[i]=-1;
inc(j,1,tot){
if(i*prime[j]>n)break;
v[i*prime[j]]++;
if(i%prime[j]==0){mu[i*prime[j]]=0;break;}
mu[i*prime[j]]=-mu[i];
}
}
}

int main(){
init();
n=read();inv=qpow(n,inf-2);
inc(i,2,n){
for(int j=1;j*j<=i;j++)if(i%j==0){
f[i]+=d[j]*mu[i/j]+inf;f[i]%=inf;
if(j*j<i)f[i]+=d[i/j]*mu[j]+inf,f[i]%=inf;
}
for(int j=1;j*j<=i;j++)if(i%j==0){
d[i]+=f[j]*(n/j);d[i]%=inf;
if(j*j<i)d[i]+=f[i/j]*(n/(i/j)),d[i]%=inf;
}
d[i]*=inv;d[i]++;d[i]%=inf;
d[i]=d[i]*n%inf*qpow(n-n/i,inf-2)%inf;
f[i]+=d[i];f[i]%=inf;
}
//inc(i,1,n)printf("%lld ",f[i]);putchar('\n');
//inc(i,1,n)printf("%lld ",d[i]);putchar('\n');
inc(i,1,n)ans+=d[i],ans%=inf;
ans*=inv;ans++;ans%=inf;
return 0*printf("%lld\n",ans);
}

$O(nlogn)$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/**
*         ┏┓    ┏┓
*         ┏┛┗━━━━━━━┛┗━━━┓
*         ┃       ┃  
*         ┃   ━    ┃
*         ┃ >   < ┃
*         ┃       ┃
*         ┃... ⌒ ...  ┃
*         ┃ ┃
*         ┗━┓ ┏━┛
*          ┃ ┃ Code is far away from bug with the animal protecting          
*          ┃ ┃ 神兽保佑,代码无bug
*          ┃ ┃           
*          ┃ ┃       
*          ┃ ┃
*          ┃ ┃           
*          ┃ ┗━━━┓
*          ┃ ┣┓
*          ┃ ┏┛
*          ┗┓┓┏━━━━━━━━┳┓┏┛
*           ┃┫┫ ┃┫┫
*           ┗┻┛ ┗┻┛
*/

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<set>
#include<bitset>
#include<assert.h>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y)/2
#define NM 200005
#define nm 105
#define pi 3.1415926535897931
using namespace std;
const ll inf=1e9+7;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}








int n,mu[NM],tot,prime[NM];
bool v[NM];
vector<int>a[NM];
ll d[NM],f[NM],inv,ans;
ll qpow(ll x,ll t){return t?qpow(sqr(x)%inf,t>>1)*(t&1?x:1ll)%inf:1ll;}
void init(){
n=1e5;mu[1]=1;
inc(i,2,n){
if(!v[i])prime[++tot]=i,mu[i]=-1;
inc(j,1,tot){
if(i*prime[j]>n)break;
v[i*prime[j]]++;
if(i%prime[j]==0){mu[i*prime[j]]=0;break;}
mu[i*prime[j]]=-mu[i];
}
}
}

int main(){
init();
n=read();inv=qpow(n,inf-2);
inc(i,1,n)for(int j=i;j<=n;j+=i)a[j].push_back(i);
inc(i,2,n){
for(int&j:a[i])f[i]+=d[j]*mu[i/j]+inf,f[i]%=inf;
for(int&j:a[i])d[i]+=f[j]*(n/j),d[i]%=inf;
d[i]*=inv;d[i]++;d[i]%=inf;
d[i]=d[i]*n%inf*qpow(n-n/i,inf-2)%inf;
f[i]+=d[i];f[i]%=inf;
}
//inc(i,1,n)printf("%lld ",f[i]);putchar('\n');
//inc(i,1,n)printf("%lld ",d[i]);putchar('\n');
inc(i,1,n)ans+=d[i],ans%=inf;
ans*=inv;ans++;ans%=inf;
return 0*printf("%lld\n",ans);
}