CF1139D Steps to One(DP,莫比乌斯反演,质因数分解)

stm这是div2的D题……我要对不住我这个紫名了……

题目链接:CF原网  洛谷

题目大意:有个一开始为空的序列。每次操作会往序列最后加一个 $1$ 到 $m$ 的随机整数。当整个序列的 $\gcd$ 为 $1$ 时停止。问这个序列的期望长度对 $10^9+7$ 取模的值。

$1\le m\le 10^5$。


首先很容易想到DP:$f_i$ 表示目前的 $\gcd$ 为 $i$,期望还要多少次才能结束。

那么有 $f_1=0$。

转移,直接枚举即可:$f_i=1+\dfrac{1}{m}\sum\limits^m_{j=1}f_{\gcd(i,j)}$。

如果出现 $\gcd(i,j)=i$(也就是 $i|j$),那么把这种情况特殊判断,那么解个方程可以得到:

$$f_i=\dfrac{1+\dfrac{1}{m}\sum\limits^m_{j=1,i\nmid j}f_{\gcd(i,j)}}{1-\lfloor\frac{m}{i}\rfloor}$$

答案为 $\dfrac{1}{m}\sum\limits^m_{i=1}(f_i+1)$。

这是 $O(m^2\log m)$ 的。我当时就是在这里卡住了,现在感觉自己是个zz……

我们套路地枚举 $\gcd$,设 $c(i,j)$ 表示有多少个 $1\le x\le m$ 满足 $\gcd(i,x)=j$。那么就有:

$$f_i=\dfrac{1+\dfrac{1}{m}\sum\limits_{j|i}f_{j}c(i,j)}{1-\lfloor\frac{m}{i}\rfloor}$$

接下来就要考虑求 $c(i,j)(j|i)$。

$$c(i,j)=\sum\limits^m_{x=1}[\gcd(i,x)=j]$$

$$c(i,j)=\sum\limits^m_{j|x}[\gcd(\frac{i}{j},\frac{x}{j})=1]$$

$$c(i,j)=\sum\limits^{\lfloor\frac{m}{j}\rfloor}_{x=1}[\gcd(\frac{i}{j},x)=1]$$

接下来有两条路可走:分解质因数(官方做法)和莫比乌斯反演(大众做法)。

那我们先来看看大众做法。


莫比乌斯反演:

$$c(i,j)=\sum\limits^{\lfloor\frac{m}{j}\rfloor}_{x=1}\sum\limits_{d|\gcd(\frac{i}{j},x)}\mu(d)$$

$$c(i,j)=\sum\limits_{d|\frac{i}{j}}\mu(d)\sum\limits^{\lfloor\frac{m}{j}\rfloor}_{d|x}1$$

$$c(i,j)=\sum\limits_{d|\frac{i}{j}}\mu(d)\lfloor\dfrac{m}{jd}\rfloor$$

此时求 $c(i,j)$ 复杂度为 $O(\sqrt{\frac{i}{j}})$。

总复杂度为 $O(\sum\limits^m_{i=2}\sum\limits_{j|i}\sqrt{\frac{i}{j}})=O(\sum\limits^m_{i=2}\sum\limits_{j|i}\sqrt{j})=O(\sum\limits^m_{j=1}\sqrt{j}\lfloor\frac{m}{j}\rfloor)\approx O(m\int^m_1j^{-\frac{1}{2}}\mathrm{d}j)=O(m\sqrt{m})$。


分解质因数:

我们不妨修改一下定义(只是为了方便):令 $c(x,y)=\sum\limits^y_{i=1}[\gcd(i,x)=1]$。那么原来的 $c(i,j)$ 就变成了现在的 $c(\frac{i}{j},\lfloor\frac{m}{j}\rfloor)$。

也就是要 $i$ 和 $x$ 的质因子集合没有交集。

我们从反向考虑,考虑与 $x$ 的质因子有交集的 $i$ 的个数。

先对 $x$ 质因数分解,设分解出的不同质因子有 $p_1,p_2\cdots p_k$。那么有 $k\le 6$。

那么与集合 $S$ 有交的 $i$ 的个数就是 $\lfloor\frac{y}{\prod S_i}\rfloor$。

然后还要再容斥一下。那么总的就是:

$$c(x,y)=y-\sum\limits_{S\in x_{pr}}(-1)^{|S|}\lfloor\frac{y}{\prod S_i}\rfloor$$

此时转移方程为:

$$f_i=\dfrac{1+\dfrac{1}{m}\sum\limits_{j|i}f_{j}c(\frac{i}{j},\lfloor\frac{m}{j}\rfloor)}{1-\lfloor\frac{m}{i}\rfloor}$$

这个可以做到 $O(2^k+\sqrt{x})$。注意最好用DFS,不要用二进制枚举,否则会退化为 $O(2^k\times k+\sqrt{x})$。(虽然也能过)

时间复杂度也是 $O(m\sqrt{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\n",ans);
}
View Code

猜你喜欢

转载自www.cnblogs.com/1000Suns/p/10656969.html