【每日一題】Steps to One (容斥+錯位相減)cf1139D

題目鏈接
前置推論:
1.長度爲1的序列只可能是一個1。
2.假設當前的序列長度爲k+1k+1,且前kk個數的gcd=agcd=a不爲1的話,那麼第k+1k+1位的數必然與a互質,所以第k+1k+1個數選擇的方案爲[1,m]中與a互質的數的個數,記get(a)get(a)[1,m][1,m]中與a互質的數的個數,get(x)get(x)可以通過容斥計算。
那麼我們需要統計的就是所有長度>=2的期望。
我們從大到小遍歷[1,m][1,m],設當前枚舉到的數爲x,我們計算所有長度爲i+12i+1\geq2且序列的前i項的gcdgcd爲x的期望,那麼可以前i項必然都是x的倍數,顯然通過求和我們可以得到一個較大的答案

i=1mxiget(x)m(i+1)\sum_{i=1}^{\infty}\lfloor\frac{m}{x}\rfloor^i\frac{get(x)}{m}(i+1)
其中get(x)m\frac{get(x)}{m}爲常數項可以拎出來單獨計算,那麼後面的i=1mxi(i+1)\sum_{i=1}^{\infty}\lfloor\frac{m}{x}\rfloor^i(i+1)就是我們要求的,這樣求和的東西就是高中常說的錯位相減法搞一下就能算出來了。
但是爲什麼說這個答案較大呢?仔細想一下,這樣生成的序列的前i項的gcd必然包含所有x的倍數。
P(dx,dy)P(dx,dy)爲序列長度爲dx且gcd爲dy的概率
那麼後半部分真正的答案就是

i=1(mxij=i+1mP(i,j)[j%i=0])(i+1)=i=1mxi(i+1)j=x+1mi=1P(i,j)(i+1)[jmod  x=0]\sum_{i=1}^{\infty}(\lfloor\frac{m}{x}\rfloor^i-\sum_{j=i+1}^mP(i,j)[j\%i=0])(i+1)= \sum_{i=1}^\infty\lfloor\frac{m}{x}\rfloor^i(i+1)-\sum_{j=x+1}^m\sum_{i=1}^\infty P(i,j)(i+1)[j\mod x=0]
我們設an[c]=i=1P(i,c)(i+1)an[c]=\sum_{i=1}^{\infty}P(i,c)(i+1),那麼an[x]=i=1mxi(i+1)j=i+1man[j][j%i=0]an[x]=\sum_{i=1}^{\infty}\lfloor\frac{m}{x}\rfloor^i(i+1)-\sum_{j=i+1}^man[j][j\% i=0],那麼長度爲i+1項且前i項的gcd爲x的真正期望就是an[x]get(x)man[x]\frac{get(x)}{m}
綜上,對每個數進行討論並計算答案即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
LL m;
const LL mod=1e9+7;
LL pm(LL x,LL y){
  LL z=1;
  while(y){
    if(y&1)z=z*x%mod;
    x=x*x%mod;
    y>>=1;
  }
  return z;
}
int a[N],p[N],cnt;
void P(){
  for(int i=2;i<N;i++){
    if(!p[i])a[++cnt]=i;
    for(int j=1;j<=cnt&&1ll*a[j]*i<N;j++){
      p[a[j]*i]=1;
      if(i%a[j]==0)break;
    }
  }
}
LL get(int y){
  vector<int>x;
  for(int i=1;i<=cnt&&1ll*a[i]*a[i]<=y;i++){
    if(y%a[i]==0){
      x.pb(a[i]);
      while(y%a[i]==0)y/=a[i];
    }
  }
  if(y>1)x.pb(y);
  int sz=x.size();
  int ans=m;
  for(int i=1;i<1<<sz;i++){
    int l=0,r=1;
    for(int j=0;j<sz;j++){
      if(1<<j&i){
        l++;
        r*=x[j];
      }
    }
    if(l&1)ans-=m/r;
    else ans+=m/r;
  }
  return ans;
}
LL _get(LL x){
  return (x*(m-x)+x*m)%mod*pm(1ll*(m-x)*(m-x)%mod,mod-2)%mod;
}
LL an[N];
int main() {
  ios::sync_with_stdio(false);
  cin>>m;P();
  LL re_m=pm(m,mod-2);
  LL ans=re_m;
  for(int i=m;i>=2;i--){
    LL x=get(i);
    LL res=_get(m/i)%mod;
    for(int j=i+i;j<=m;j+=i)res-=an[j],res=(res+mod)%mod;
    an[i]=res;
    ans+=res*x%mod*re_m%mod;
    ans%=mod;
  }
  cout<<ans<<'\n';
  return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章