UVA 11762 Race to 1

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\n",Case,dfs(n));
}

int main()
{
	int T;cin>>T;
	prework();
	while(T--)Case++,work();
	return 0;
}

posted @ 2017-09-06 22:43  PIPIBoss  阅读(105)  评论(0编辑  收藏  举报