CF1139D Steps to One

很好的一道题。

最开始我想的是 dp,但是在序列 gcd 不变的时候有点想不明白。

后来看了几位大佬的思路,终于会了。

CF1139D Steps to One

题目大意:

一个初始为空的数列,每次等概率随机在末尾放入一个 1m 之间的数,序列 gcd=1 时结束,问序列长度的期望。

题目思路:

如果你实在是不会什么方法,那就直接推式子,先将期望的定义写出来,之后一步步化简。

X 为步数:

(解释在后面)

式子:

(1)E[X]=jjP(X=j)(2)=jij1P(X=j)(3)=ijiP(X=j)(4)=iP(Xi)(5)=1+iP(X>i)(6)=1+i(1P(gcdi(ai)=1))(7)=1+imik1μ(k)mkimi(8)=1+imimik2μ(k)mkimi(9)=1ik2μ(k)mkimi(10)=1k2μ(k)i(mkm)i(11)=1k2μ(k)mkmlimn1(mkm)n1mkm(12)=1k2μ(k)mkm11mkm(13)=1k2μ(k)mkmmk

其中用了期望定义、容斥、莫反、等比数列求和公式。

解释:

(1) 没什么好说的,就是期望的定义。

(2)(3)(4) 就是先将 j 拆开,然后交换求和顺序,之后再将其中一个求和拍到概率种统一算。

其实这几步甚至可以不用推,直接瞪眼法可以一步想到,还是挺套路的。如果是第一次见,可以记一下,当套路食用。

(5) 就是将等号提出来,之后 (6) 就是将式子按照题目的定义将 P 写出来。

(7) 这里运用了莫比乌斯反演,这玩意几个结论就好。

同时注意,由于每个位置选某个数的概率是 1m,所以 i 个数就是 1mi,之后又将 1 挪到了分数线上面。

(8) 就是把 k=1 拿出来,(9) 是把符号提出去,之后变换求和顺序到 (10)

注意到 (10) 就是个等比数列求和,直接套公式到 (11)

又由于 mkm<1,所以当 n 趋近于 时,它的 n 次方就是 0

那么就变到 (12),之后乘在一起就是 (13)

到了这一步,这个式子就十分的简洁了,可以直接枚举 k,上界显然就是 m 因为 k>m 时对答案的贡献就都是 0

复杂度 O(m)

Code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 1000000007ll
inline int read(){
	int rt=0;	char g=getchar();
	while(g<'0'||g>'9')	g=getchar();
	while(g>='0'&&g<='9')	rt=(rt<<3)+(rt<<1)+g-'0',g=getchar();
	return rt;
}
inline int KSM(int A,int k)
{
	if(!k)	return 1;
	ll rt=KSM(A,k>>1);
	(rt*=rt)%=mod;
	if(k&1)	(rt*=1ll*A)%=mod;
	return rt;
}

int n;
ll ans;
bool ck[100005];
ll mu[100005],p[100005],num;
int main()
{
	n=read();	mu[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!ck[i])	p[++num]=i,mu[i]=-1;
		for(int j=1;j<=num&&p[j]*i<=n;j++)
		{
			ck[p[j]*i]=1;
			if(!(i%p[j]))	break;
			mu[p[j]*i]=-mu[i];
		}
	}
	for(int i=2;i<=n;i++)(ans+=mu[i]*(n/i)%mod*KSM((n-n/i),(mod-2))%mod)%=mod;
	printf("%lld",(1ll-ans+mod)%mod);
	return 0;
}
posted @   YT0104  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示