一、原题
题目传送门(vjudge有密码)
题目传送门(lightOJ)
Rimi learned a new thing about integers, which is - any positive integer greater than 1 can be divided by its divisors. 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 divisor of D (1 to D). Then he divides Dby the number to obtain new D. He repeats this procedure until D becomes 1. What is the expected number of moves required for N to become 1.
InputInput starts with an integer T (≤ 10000), denoting the number of test cases.
Each case begins with an integer N (1 ≤ N ≤ 105).
OutputFor each case of input you have to print the case number and the expected value. Errors less than10-6 will be ignored.
Sample Input3
1
2
50
Sample OutputCase 1: 0
Case 2: 2.00
Case 3: 3.0333333333
二、题目大意
给一个正整数n,现在等概率地选择n的一个因数(包括1和n本身,不一定是质数),拿n除以因数得到一个新的n,不断重复此过程直到n变为1。求变为1所需次数的期望。
三、分析
设期望为e=f(n),n的因数为 ai (不包括1) 和 1,因数的个数为cnt,则选取每个因数的概率p=1/cnt,当n为1时f(1)=0
则:
e=∑(f(n/a1)*p+1)+e*p
=p*∑f(n)+cnt+e*p
移项将e移到左边,并化简得
(1-p)*e=p*∑f(n)
e=p/(1-p)*∑f(n)=1/(cnt-1)*∑f(n)
方法:记忆化搜索没得说。
考虑好边界条件,当n为质数时f(n)=2,当n为1时f(1)=0
求因数时直接暴力求 ,记得一次求两个,即i从2到sqrt(x)而不是2到x,此处是tle or not的关键。
四、AC代码
#include<bits/stdc++.h>
using namespace std;
int const maxn=1e5+10;
int Mark[maxn]={0};//0表示素数
int prime[maxn];
int Prime() //素数筛求1e5以内的质数
{
int index=0;
int i,j;
for( i = 2; i<maxn; i++)
{
if(Mark[i] == 0)
prime[index++]=i;
for(int j=0;j<index && prime[j]*i<maxn;j++)
{
Mark[i*prime[j]]=1;
if(i % prime[j] == 0)
break;
}
}
Mark[1]=1;
return index;
}
double lst[maxn];
double dfs(int x)
{
if(lst[x])
return lst[x];
if(x==1)
return 0;
if(Mark[x]==0)
{
return 2;
}
int i;
int n=2;
double sum=0;
for(i=2;i*i<=x;i++)
{
if(x%i==0)
{
n++;
sum+=dfs(i);
if(i*i!=x)
{
sum+=dfs(x/i);
n++;
}
}
}
sum+=n;
return lst[x]=sum/(n-1);
}
int main()
{
int T,n;
Prime();
cin>>T;
int cs=1;
while(T--)
{
scanf("%d",&n);
printf("Case %d: %.8f\n",cs++,dfs(n));
}
}