设f(x)表示x转移到1需要的次数的期望,p(x)为不超过x的素数的个数,其中能整除x的有g(x)个
则有(1-g(x)/p(x))的概率下一步还是转移到x,剩下的情况各有1/p(x)的概率转移到x/y
根据全期望公式,f(x) = 1 + (1-g(x)/p(x)) * f(x) + sum{ 1/p(x) * f(x/y) | y是能整除x且不超过x的素数 }
代码是用记忆化搜索计算f的
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 using namespace std; 5 6 const int maxn = 1000000; 7 bool vis[maxn + 10]; 8 int prime[100000], pcnt = 0; 9 10 void prime_table() 11 { 12 int m = sqrt(maxn + 0.5); 13 for(int i = 2; i <= m; i++) if(!vis[i]) 14 for(int j = i*i; j <= maxn; j += i) vis[j] = true; 15 for(int i = 2; i <= maxn; i++) if(!vis[i]) prime[pcnt++] = i; 16 } 17 18 double d[maxn + 10]; 19 20 double dp(int x) 21 { 22 if(x == 1) return 0; 23 if(vis[x]) return d[x]; 24 vis[x] = 1; 25 double& ans = d[x]; 26 int p = 0, g = 0; 27 for(int i = 0; i < pcnt && prime[i] <= x; i++) 28 { 29 p++; 30 if(x % prime[i] == 0) { ans += dp(x / prime[i]); g++; } 31 } 32 ans = (ans + p) / g; 33 return ans; 34 } 35 36 int main() 37 { 38 //freopen("in.txt", "r", stdin); 39 40 prime_table(); 41 memset(vis, false, sizeof(vis)); 42 int T; 43 scanf("%d", &T); 44 for(int kase = 1; kase <= T; kase++) 45 { 46 int x; 47 scanf("%d", &x); 48 printf("Case %d: %.10f\n", kase, dp(x)); 49 } 50 51 return 0; 52 }
代码君
时间: 2024-10-10 16:00:40