CF1139D Steps to One
很好的一道题。
最开始我想的是 \(dp\),但是在序列 \(gcd\) 不变的时候有点想不明白。
后来看了几位大佬的思路,终于会了。
CF1139D Steps to One
题目大意:
一个初始为空的数列,每次等概率随机在末尾放入一个 \(1\) 到 \(m\) 之间的数,序列 \(gcd=1\) 时结束,问序列长度的期望。
题目思路:
如果你实在是不会什么方法,那就直接推式子,先将期望的定义写出来,之后一步步化简。
令 \(X\) 为步数:
(解释在后面)
式子:
其中用了期望定义、容斥、莫反、等比数列求和公式。
解释:
\((1)\) 没什么好说的,就是期望的定义。
\((2)、(3)、(4)\) 就是先将 \(j\) 拆开,然后交换求和顺序,之后再将其中一个求和拍到概率种统一算。
其实这几步甚至可以不用推,直接瞪眼法可以一步想到,还是挺套路的。如果是第一次见,可以记一下,当套路食用。
\((5)\) 就是将等号提出来,之后 \((6)\) 就是将式子按照题目的定义将 \(P\) 写出来。
\((7)\) 这里运用了莫比乌斯反演,这玩意几个结论就好。
同时注意,由于每个位置选某个数的概率是 \(\frac{1}{m}\),所以 \(i\) 个数就是 \(\frac{1}{m^i}\),之后又将 \(1\) 挪到了分数线上面。
\((8)\) 就是把 \(k=1\) 拿出来,\((9)\) 是把符号提出去,之后变换求和顺序到 \((10)\)。
注意到 \((10)\) 就是个等比数列求和,直接套公式到 \((11)\)。
又由于 \(\frac{\lfloor\frac{m}{k}\rfloor}{m}<1\),所以当 \(n\) 趋近于 \(\infty\) 时,它的 \(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;
}