LightOJ - 1038 Race to 1 Again(期望)

Posted pixel-teee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LightOJ - 1038 Race to 1 Again(期望)相关的知识,希望对你有一定的参考价值。

题意:Rimi学到了一个关于整数的知识,就是任何大于1的整数可以被它的任何因子整除。所以,他准备玩这个特性。他选择了一个整数N,每一次,他随机的选择这个整数的因子,并且整除这个数。直到使得这个数变成1。求N到1的期望值。

分析:一个数可以被它的因子整除,那么整除完的新值也是它的因子。我们定义f[i]:i到1的期望值,那么(f[i] = (f[num[1]] + 1 + f[num[2]] + 1 + f[num[3]] + 1 + ... + f[num[n]] + 1) / num,)num[]数组是i的因子数组,我们可以得出num[n] = i,所以我们可以化简如下:

(f[i] * num = f[num[1]] + f[num[2]] + f[num[3]] + ... + f[num[n]] + num)
(f[i] * (num - 1) = f[num[1]] + f[num[2]] + f[num[3]] + ... + num)
(f[i] = frac{f[num[1]] + f[num[2]] + f[num[3]] + ...}{num - 1})

这道题的数N很大,不能使用记忆化搜索,因为记忆化搜索不能把所有的状态搜到,所以要预处理出所有的值。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
#include <algorithm>

using namespace std;
const int N = 100005;
double f[N];
vector<int> v[N];

int main()
{
    int t;
    scanf("%d", &t);

    //预处理出所有因子
    for(int i = 2; i < N; ++i)
        for(int j = 1; j <= i / j; ++j)
        {
            if(i % j == 0)
            {
                v[i].push_back(j);
                if(j * j != i) v[i].push_back(i / j);
            }
        }
    for(int i = 2; i < N; ++i)
    {
        int sz = v[i].size();
        for(int j = 0; j < sz; ++j)
        {
            if(v[i][j] != i) f[i] += f[v[i][j]];
        }
        f[i] = (f[i] + sz) / (sz - 1);
    }
    int c = 0;
    while(t--)
    {
        int n;
        scanf("%d", &n);
        printf("Case %d: %.6lf
", ++c, f[n]);
    }
    return 0;
}









以上是关于LightOJ - 1038 Race to 1 Again(期望)的主要内容,如果未能解决你的问题,请参考以下文章

LightOJ 1038 Race To 1 Again(概率DP)

LightOJ - 1038 Race to 1 Again(期望)

LightOJ 1038 - Race to 1 Again (给一个数,用这个数的因数除以这个数,直到为1时,求除的次数的期望。)(概率)

lightoj1038_概率dp

LightOJ - 1038(概率&DP)

lightoj1038(数学概率与期望)