Dilu have learned a new thing about integers, which is - any positive integer greater than 1 can be
divided by at least one prime number less than or equal to that number. So, he is now playing with
this property. He selects a number N . And he calls this D.
In each turn he randomly chooses a prime number less than or equal to D. If D is divisible by the
prime number then he divides D by the prime number to obtain new D. Otherwise he keeps the old
D. He repeats this procedure until D becomes 1. What is the expected number of moves required for
N to become 1.
题目大意:给出一个数N,每次随机选出一个小于N的素数,如果能整除N那么N变为N/x,否则N不变,求变为1的期望次数
解题报告:
(f[i]=1+f[i]*(1-g[i]/p[i])+sum_{j|i}f[j]/p[i])
其中p[i]为小于i的质数的数量,g[i]为i的素因子个数
(1-g[i]/p[i])代表选出的素数不能整除i,后面则表示整除
对于一开始的1,表示选的是i本身
移向化简之后:(f[i]=(p[i]+sum_{j|i}f[j]/p[i])/g[i])
可以用记忆化搜索实现
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N=1000005;
int n,prime[N],num=0,Case=0;bool d[N];double f[N];
void prework(){
f[1]=-1;f[0]=-1;
for(int i=2;i<N;i++){
if(!d[i])prime[++num]=i;f[i]=-1;
for(int j=1;j<=num && prime[j]*i<N;j++){
d[i*prime[j]]=true;
if(i%prime[j]==0)break;
}
}
}
double dfs(int x){
if(x==1)return 0.0;
if(f[x]!=-1)return f[x];
double ret=0,tot=0,sum=0;
for(int i=1;i<=num && prime[i]<=x;i++){
if(x%prime[i]==0)tot++,ret+=dfs(x/prime[i]);
sum++;
}
ret=(ret+sum)/tot;
return f[x]=ret;
}
void work()
{
scanf("%d",&n);
printf("Case %d: %lf
",Case,dfs(n));
}
int main()
{
int T;cin>>T;
prework();
while(T--)Case++,work();
return 0;
}