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
CF1139D Steps to One(DP,莫比烏斯反演,質因數分解)