lightoj1038(期望dp)

时间:2023-03-09 05:44:37
lightoj1038(期望dp)

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

 #include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
const int INF = <<;
/* */
const int N = + ;
double dp[N];
int cnt[N];
bool vis[N];
void init()
{
dp[] = ;
for (int di = ; di < N; ++di)//对于每一个di,枚举它的倍数
{
cnt[di]+=;
dp[di] = (dp[di] / cnt[di] + )*cnt[di] / (cnt[di] - );
for (int i = di*; i < N; i += di)
{
cnt[i]++;
dp[i] += dp[di];
} }
}
int main()
{
int t, n;
scanf("%d", &t);
init();
for (int k = ; k <= t; ++k)
{
scanf("%d", &n);
printf("Case %d: %.10lf\n",k, dp[n]);
}
return ;
}