stm这是div2的D题……我要对不住我这个紫名了……
题目大意:有个一开始为空的序列。每次操作会往序列最后加一个 $1$ 到 $m$ 的随机整数。当整个序列的 $gcd$ 为 $1$ 时停止。问这个序列的期望长度对 $10^9+7$ 取模的值。
$1le mle 10^5$。
首先很容易想到DP:$f_i$ 表示目前的 $gcd$ 为 $i$,期望还要多少次才能结束。
那么有 $f_1=0$。
转移,直接枚举即可:$f_i=1+dfrac{1}{m}sumlimits^m_{j=1}f_{gcd(i,j)}$。
如果出现 $gcd(i,j)=i$(也就是 $i|j$),那么把这种情况特殊判断,那么解个方程可以得到:
$$f_i=dfrac{1+dfrac{1}{m}sumlimits^m_{j=1,i mid j}f_{gcd(i,j)}}{1-lfloorfrac{m}{i} floor}$$
答案为 $dfrac{1}{m}sumlimits^m_{i=1}(f_i+1)$。
这是 $O(m^2log m)$ 的。我当时就是在这里卡住了,现在感觉自己是个zz……
我们套路地枚举 $gcd$,设 $c(i,j)$ 表示有多少个 $1le xle m$ 满足 $gcd(i,x)=j$。那么就有:
$$f_i=dfrac{1+dfrac{1}{m}sumlimits_{j|i}f_{j}c(i,j)}{1-lfloorfrac{m}{i} floor}$$
接下来就要考虑求 $c(i,j)(j|i)$。
$$c(i,j)=sumlimits^m_{x=1}[gcd(i,x)=j]$$
$$c(i,j)=sumlimits^m_{j|x}[gcd(frac{i}{j},frac{x}{j})=1]$$
$$c(i,j)=sumlimits^{lfloorfrac{m}{j} floor}_{x=1}[gcd(frac{i}{j},x)=1]$$
接下来有两条路可走:分解质因数(官方做法)和莫比乌斯反演(大众做法)。
那我们先来看看大众做法。
莫比乌斯反演:
$$c(i,j)=sumlimits^{lfloorfrac{m}{j} floor}_{x=1}sumlimits_{d|gcd(frac{i}{j},x)}mu(d)$$
$$c(i,j)=sumlimits_{d|frac{i}{j}}mu(d)sumlimits^{lfloorfrac{m}{j} floor}_{d|x}1$$
$$c(i,j)=sumlimits_{d|frac{i}{j}}mu(d)lfloordfrac{m}{jd} floor$$
此时求 $c(i,j)$ 复杂度为 $O(sqrt{frac{i}{j}})$。
总复杂度为 $O(sumlimits^m_{i=2}sumlimits_{j|i}sqrt{frac{i}{j}})=O(sumlimits^m_{i=2}sumlimits_{j|i}sqrt{j})=O(sumlimits^m_{j=1}sqrt{j}lfloorfrac{m}{j} floor)approx O(mint^m_1j^{-frac{1}{2}}mathrm{d}j)=O(msqrt{m})$。
分解质因数:
我们不妨修改一下定义(只是为了方便):令 $c(x,y)=sumlimits^y_{i=1}[gcd(i,x)=1]$。那么原来的 $c(i,j)$ 就变成了现在的 $c(frac{i}{j},lfloorfrac{m}{j} floor)$。
也就是要 $i$ 和 $x$ 的质因子集合没有交集。
我们从反向考虑,考虑与 $x$ 的质因子有交集的 $i$ 的个数。
先对 $x$ 质因数分解,设分解出的不同质因子有 $p_1,p_2cdots p_k$。那么有 $kle 6$。
那么与集合 $S$ 有交的 $i$ 的个数就是 $lfloorfrac{y}{prod S_i} floor$。
然后还要再容斥一下。那么总的就是:
$$c(x,y)=y-sumlimits_{Sin x_{pr},S evarnothing}(-1)^{|S|+1}lfloorfrac{y}{prod S_i} floor$$
当然也可以写成:(这是代码中的写法)
$$c(x,y)=sumlimits_{Sin x_{pr}}(-1)^{|S|}lfloorfrac{y}{prod S_i} floor$$
此时转移方程为:
$$f_i=dfrac{1+dfrac{1}{m}sumlimits_{j|i}f_{j}c(frac{i}{j},lfloorfrac{m}{j} floor)}{1-lfloorfrac{m}{i} floor}$$
这个可以做到 $O(2^k+sqrt{x})$。注意最好用DFS,不要用二进制枚举,否则会退化为 $O(2^k imes k+sqrt{x})$。(虽然也能过)
时间复杂度也是 $O(msqrt{m})$。
由于大多数人写的都是莫比乌斯反演,我就写一发质因数分解给大家。
#include<bits/stdc++.h> using namespace std; const int maxn=100010,mod=1000000007; #define FOR(i,a,b) for(int i=(a);i<=(b);i++) #define ROF(i,a,b) for(int i=(a);i>=(b);i--) #define MEM(x,v) memset(x,v,sizeof(x)) inline int read(){ char ch=getchar();int x=0,f=0; while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return f?-x:x; } int m,f[maxn],fac[7],fl; inline int qpow(int a,int b){ int ans=1; for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) ans=1ll*ans*a%mod; return ans; } int dfs(int dep,int pro,int sgn,int up){ //dep表示正在枚举第几个质因子,pro表示S的乘积,sgn表示容斥系数(1或-1),up表示上界 if(dep>fl) return up/pro*sgn; else return dfs(dep+1,pro,sgn,up)+dfs(dep+1,pro*fac[dep],-sgn,up); } int cnt(int x,int y){ fl=0; for(int i=2;i*i<=x;i++) if(x%i==0){ fac[++fl]=i; while(x%i==0) x/=i; } if(x>1) fac[++fl]=x; return dfs(1,1,1,y); } int main(){ m=read();int inv=qpow(m,mod-2); f[1]=0; FOR(i,1,m){ if(i!=1){ //最后要除以m,加1再除以1-m/i f[i]=1ll*f[i]*inv%mod; f[i]=(f[i]+1)%mod; f[i]=1ll*f[i]*qpow((1-1ll*(m/i)*inv%mod+mod)%mod,mod-2)%mod; } FOR(j,2,m/i) f[i*j]=(f[i*j]+1ll*f[i]*cnt(j,m/i))%mod; //枚举i的倍数,f[i*j]+=f[i]*c((i*j)/i,m/i) } int ans=0; FOR(i,1,m) ans=(ans+f[i]+1)%mod; //累加答案 ans=1ll*ans*inv%mod; printf("%d ",ans); }