天梯赛
题解
]
天梯赛 2021 L3-3 可怜的简单题题解
题意:重复从 $1,n$ 中随机加一个数到序列末,直至序列的 $\gcd$ 为 $1$ 为止,序列初始为空,求序列的期望长度。
假设序列的长度为 $k$,那么不难算出每个数都是 $d$ 的倍数的概率 $g_d$
\[g_d=\left(\frac{\lfloor n/d\rfloor}n\right)^k\]不妨设 $f_n$ 表示长度为 $k$,整个序列的 $\gcd$ 为 $n$ 的概率,不难看出
\[g_d=\sum_{d\mid n}f_n\]也就是 $g=1\ast f$,莫反一下,$f=\mu\ast g$
\[f_n=\sum_{n\mid d}\mu(d/n)g_d\]我们只需要计算 $f_1$,也就是 $\gcd=1$ 的概率
\[f_1=\sum_{d}\mu(d)g_d=\sum_{i=1}^n\mu(i)\left(\frac{\lfloor n/i\rfloor}n\right)^k\]这里只枚举到 $n$ 是因为 $i>n$ 时 $g_i=0$
因此,设长度为 $k$ 时序列的 $\gcd=1$ 的概率为 $t(k)$,那么
\[t(k)=\sum_{i=1}^n\mu(i)\left(\frac{\lfloor n/i\rfloor}n\right)^k\]令 $T$ 为停时,那么
\[\begin{aligned} \mathbb E[T]&=\sum_{k\ge1}k(t(k-1)-t(k))\\ &=\sum_{k\ge0}t(k)\\ &=\sum_{k\ge0}\sum_{i=1}^n\mu(i)\left(\frac{\lfloor n/i\rfloor}n\right)^k\\ &=\sum_{i=1}^n\mu(i)\sum_{k\ge0}\left(\frac{\lfloor n/i\rfloor}n\right)^k\\ &=\sum_{i=1}^n\mu(i)\frac1{1-\frac{\lfloor n/i\rfloor}n}\\ &=\sum_{i=1}^n\mu(i)\frac n{n-\lfloor n/i\rfloor}\\ \end{aligned}\]按 $\lfloor n/i\rfloor$ 整除分块即可,前面 $\mu$ 前缀和采用杜教筛,复杂度 $\mathcal O(n^{2/3})$
但是模数 $P\le10^{12}$ 是来恶心大家的吗?
#include<bits/stdc++.h>
#define siz(x) int((x).size())
#define all(x) std::begin(x),std::end(x)
#define fi first
#define se second
#define int loli
using namespace std;
using unt=unsigned;
using loli=long long;
using lolu=unsigned long long;
using pii=pair<int,int>;
mt19937_64 rng(random_device{}());
constexpr int N=1e7+7;
bool pr[N];
int mu[N],n,P;
loli mv[N];
basic_string<int>pt;
unordered_map<loli,loli>mw;
loli calc_mu(loli n){
if(n<N)return mv[n];
if(mw.count(n))return mw[n];
loli s=1;
for(loli l=2,r;l<=n;l=r+1){
r=n/(n/l);
s-=(r-l+1)*calc_mu(n/l);
}
return mw[n]=s;
}
using venti=__int128_t;
loli qpow(venti x,venti y){
venti z=1;
for(;y;y>>=1,x=x*x%P)
if(y&1)z=z*x%P;
return z;
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(false);cin.tie(nullptr);
mu[1]=mv[1]=1;
for(int i=2;i<N;i++){
if(!pr[i])pt+=i,mu[i]=-1;
for(int j:pt){
if(i*j>=N)break;
pr[i*j]=true;
if(i%j==0){
mu[i*j]=0;
break;
}
mu[i*j]=-mu[i];
}
mv[i]=mv[i-1]+mu[i];
}
cin>>n>>P;
venti ans=1;
for(int l=2,r;l<=n;l=r+1){
r=n/(n/l);
venti t1=calc_mu(r)-calc_mu(l-1);
venti t2=venti(n/l)*qpow((n-(n/l)),P-2)%P;
ans=(ans-t1*t2%P+P)%P;
}
cout<<loli(ans);
return 0;
}