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.
[We say that an integer is said to be prime if its divisible by exactly two different integers. So, 1 is not
a 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 the
next 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 turn
required. 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
题意:给出一个整数N,每次可以在不超过N的素数中随机选择一个P,如果P是N的约数,则把N变成N/P,否则N不变。问平均情况下需要多少次选择,才能把N变成1.
题解:记录dp[n] 表示 N = n是答案是多少
dp[n] = 1 + ∑dp[素数因子] * 1/素数总和 + ∑dp[x] * (x为非因子素数)/ 素数总和
记忆化爆搜就可以
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> using namespace std ; typedef long long ll; const int N=1000000; int H[N + 5],P[N],cnt,vis[N + 5]; double dp[N + 6]; void prime_table() { H[1] = 1; for(int i = 2 ; i <= N ; i++) { if(!H[i]) { P[++cnt] = i; for(int j = 2 * i ; j <= N ; j += i) H[j] = 1; } } } double dfs(int n) { if(vis[n]) return dp[n]; if(n == 1) return dp[n] = 0; double& ans = dp[n]; int sum = 0, g = 0; vis[n] = 1; for(int i = 1 ; i <= cnt && P[i] <= n; i++) { sum ++; if(n % P[i] == 0) { ans += dfs(n / P[i]); }else g++; } return ans = (ans + sum) / (sum - g); } int main () { cnt = 0; prime_table(); int T, cas = 1, n; scanf("%d",&T); while(T--) { scanf("%d",&n); dfs(n); printf("Case %d: %.10f\n", cas++, dp[n]); } return 0; }