lightoj1038(期望dp)

给定一个数字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
",k, dp[n]);
49     }
50     return 0;
51 }
View Code
原文地址:https://www.cnblogs.com/justPassBy/p/4746140.html