原题: http://codeforces.com/problemset/problem/1139/D
题意:
给出一个n(<=1e5)和空的数组,你每次会选出1~m中的任意一个数放入数组,当数组的gcd等于1时结束,问数组长度的期望。
解析:
问题一: 1~n中有多少个数与x的gcd等于d
令
,
显然有:
莫比乌斯反演:
因为 的定义要求 ,而一部分 虽然是d的倍数,但是不是x的因子,这部分的答案显然是0。
所以这个问题的答案为:
而找哪部分 只需要找 即可。
问题二: 如何求解
设
为
到达
的期望步数,转移方程为:
就是说,x走一步后的结果的平均期望。这个
是包含
本身的,所以得:
最后,第一步每个情况都有 的概率走到,所以答案为
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
const int maxn=100009;
const LL mod=1e9+7;
int u[maxn];
int pri[maxn>>1],now;
bool vis[maxn];
int g[maxn],f[maxn];
int n;
LL Pow(LL a,LL b){
LL res=1;
while(b){
if(b&1)res=res*a%mod;
a=a*a%mod;b>>=1;
}
return res;
}
void init(){
u[1]=1;
rep(i,2,n){
if(!vis[i]){
pri[++now]=i;
u[i]=-1;
}
for(int j=1;j<=now&&pri[j]*i<=n;j++){
vis[pri[j]*i]=1;
if(i%pri[j]==0){
u[pri[j]*i]=0;
break;
}
u[pri[j]*i]=-u[i];
}
}
}
LL dp[maxn];
vector<int>son[maxn];
int deal(int x,int d){
x/=d;
int res=0;
rep(i,0,son[x].size()-1){
int j=son[x][i];
res+=u[j]*(n/j/d);
}
res+=u[x]*(n/x/d);
return res;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
init();
rep(i,1,n){
for(int j=i+i;j<=n;j+=i){
son[j].push_back(i);
}
}
LL invn=Pow(n,mod-2);
LL ans=0;
rep(i,1,n){
LL sum=n;
rep(j,0,son[i].size()-1){
int s=son[i][j];
sum=(sum+deal(i,s)*dp[s])%mod;
}
sum=sum*Pow(n-(n/i),mod-2)%mod;
dp[i]=sum;
ans=(ans+dp[i])%mod;
}
cout<<(ans*invn%mod+1)%mod<<endl;
}