[UVA 11762] Race to 1

《训练指南》 P143

概率DP,数学问题

Dilu have learned a new thing about integers, which is - any positive integer greater than 1 can bedivided by at least one prime number less than or equal to that number. So, he is now playing withthis 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 theprime number then he divides D by the prime number to obtain new D. Otherwise he keeps the oldD. He repeats this procedure until D becomes 1. What is the expected number of moves required forN to become 1.[We say that an integer is said to be prime if its divisible by exactly two different integers. So, 1 is nota prime, by definition. List of first few primes are 2, 3, 5, 7, 11, ...]

Input

Input will start with an integer T (T ≤ 1000), which indicates the number of test cases. Each of thenext T lines will contain one integer N (1 ≤ N ≤ 1000000).

Output

For each test case output a single line giving the case number followed by the expected number of turnrequired. Errors up to 1e-6 will be accepted.

Sample Input

3

1

3

13

Sample Output

Case 1: 0.0000000000

Case 2: 2.0000000000

Case 3: 6.0000000000


DP关键点在于dp[i] 有可能会转移回自己。此时需要进行数学上的变换,使得dp[i] 在等式的左边。


dp[i] = 1 + dp[i]*( 1- divn/ptot ) + sigma( dp[ i/div ] ) / ptot ;


dp[i] = ( ptot + sigma( dp[ i/div ] ) ) / divn;


ptot为小于 i 的质数个数, divn 为能整除 i 的 质数个数, div为能整除 i 的质数。


另外 maxn 比较大,我第一次用的预处理,就连本机都爆了。改成记忆化搜索可以只计算需要的值,就能A。似乎一般的DP都可以用记忆化搜索的形式来进行,既提高效率,又方便理解,学到了。


#include <cstdio>
#include <cstring>
#include <cstdlib>

using namespace std;
const int maxn = 1000010, prinum = 99999;

bool nprime[maxn];
int plist[1500000];
int lp;

double dfs(int);
double dp[maxn];
bool dvis[maxn];

int main()
{
	for(int i=2; i<=1001; i++)
	{
		if(!nprime[i])
		{
			int now = i*2;
			while(now < maxn)
			{
				nprime[now] = 1;
				now += i;
			}
		}
	}
	for(int i=2; i<maxn; i++)
		if(!nprime[i])
		{
			lp++;
			plist[lp] = i;
		}

	dp[1] = 0;
	dvis[1] = 1;
	
	int T;
	scanf("%d", &T);
	for(int i=1; i<=T; i++)
	{
		int n;
		scanf("%d", &n);
		printf("Case %d: %.6lf\n", i, dfs(n));
	}
}

double dfs(int now)
{
	if(dvis[now]) return dp[now];
	dvis[now] = 1;
	int tot = 0, divn = 0;
	double ans = 0;
	for(int i=1; i<=lp&&plist[i]<=now; i++)
	{
		tot++;
		if(now%plist[i] == 0)
		{
			divn++;
			ans += dfs(now/plist[i]);
		}
	}
	
	ans = (ans+tot)/divn;
	dp[now] = ans;
	return ans;
}


2015.11.2


你可能感兴趣的:([UVA 11762] Race to 1)