题意:给定一个数N, 要你从小于等于N的素数中找出能够给N整除的素因子, 即该素数可以被N整除, 使得新的N = N/prime[i], 数N=N除以该素因子得到新的N, 知道N=1为止, 现在要你求出平均情况下随机选素数的次数的期望.
分析:概率dp+记忆化搜索。设dp[i]为i的期望,fac为素因子的数量,tot为素数数量,,则dp[i]=1+(1-fac/tot)*dp[i]+Σdp[i/pk]/tot整理得dp[i]=(tot+Σdp[i/pk])/fac;
#include<cstdio>
#include<algorithm>
#include<cstring>
#define MAX_N 1000001
using namespace std;
double dp[MAX_N];
bool isprime[MAX_N];
int prime[MAX_N];
int cnt;
void euler_sieve(int n)
{
cnt=0;
memset(isprime,true,sizeof(isprime));
isprime[0]=false;
isprime[1]=false;
for(int i=2;i<n;i++)
{
if(isprime[i])
prime[cnt++]=i;
for(int j=0;j<cnt&&prime[j]*i<n;j++)
{
isprime[i*prime[j]]=false;
if(!(i%prime[j]))
break;
}
}
return ;
}
double DP(int n)
{
if(n==1)
return 0;
if(dp[n])
return dp[n];
double ans=0;
int fac=0;
int tot=0;
for(int j=0;j<cnt&&prime[j]<=n;j++)
{
tot++;
if(n%prime[j]==0)
{
fac++;
ans+=DP(n/prime[j]);
}
}
ans=((double)tot+ans)/(double)fac;
return dp[n]=ans;
}
int main(void)
{
memset(dp,0,sizeof(dp));
euler_sieve(MAX_N);
int cas=1;
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
printf("Case %d: %.10lf\n",cas++,DP(n));
}
return 0;
}