给定一个数字d,随机选择一个d的约数,然后让d除以这个约数,形成新的d,不断继续这个步骤,知道d=1为止,
要我们求将d变为1的期望次数
设d1,d2...dj是除以约数后,形成的行的d,且dj==d
那么dp[i] = 1/j*dp[d1] + 1/j*dp[d2]+...+1/j*dp[dj] + 1
(j-1)/j*dp[i] = 1/j*dp[d1] + 1/j*dp[d2]+...+1/j*dp[dj-1] + 1
所以dp[i] = (1/j*dp[d1] + 1/j*dp[d2]+...+1/j*dp[dj-1] + 1)*j/(j-1)
计算dp的时候,我们可以对于每个数,枚举它的倍数,这样的话,时间复杂度是nlogn
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <algorithm> 5 #include <iostream> 6 #include <queue> 7 #include <stack> 8 #include <vector> 9 #include <map> 10 #include <set> 11 #include <string> 12 #include <math.h> 13 using namespace std; 14 #pragma warning(disable:4996) 15 #pragma comment(linker, "/STACK:1024000000,1024000000") 16 typedef long long LL; 17 const int INF = 1<<30; 18 /* 19 20 */ 21 const int N = 100000 + 10; 22 double dp[N]; 23 int cnt[N]; 24 bool vis[N]; 25 void init() 26 { 27 dp[1] = 0; 28 for (int di = 2; di < N; ++di)//对于每一个di,枚举它的倍数 29 { 30 cnt[di]+=2; 31 dp[di] = (dp[di] / cnt[di] + 1)*cnt[di] / (cnt[di] - 1); 32 for (int i = di*2; i < N; i += di) 33 { 34 cnt[i]++; 35 dp[i] += dp[di]; 36 } 37 38 } 39 } 40 int main() 41 { 42 int t, n; 43 scanf("%d", &t); 44 init(); 45 for (int k = 1; k <= t; ++k) 46 { 47 scanf("%d", &n); 48 printf("Case %d: %.10lf\n",k, dp[n]); 49 } 50 return 0; 51 }
时间: 2024-11-08 12:21:08