Race to 1 Again(概率+dp动态规划)

43 篇文章 0 订阅
23 篇文章 0 订阅

Race to 1 Again(概率+dp动态规划)

judge:LightOJ 1038
vjudge:VJudge
Time limit 2000 ms
Memory limit 32768 kB
OS Linux

描述在这里插入图片描述

Rimi learned a new thing about integers, which is - any positive integer greater than 1 can be divided by its divisors. So, he is now playing with this property. He selects a number N. And he calls this D.
LightOJ 1038

Input

LightOJ 1038

Output

LightOJ 1038

Sample Input

3
1
2
50

Sample Output

Case 1: 0
Case 2: 2.00
Case 3: 3.0333333333

题意

Rimi学到了一个关于整数的新知识,即任何大于1的正整数都可以被除数除。所以,他现在在玩这个游戏。他选择了一个数字 n n n,然后把它叫做 D D D

在每一轮中,他随机选择一个除数( 1 1 1 D D D)。然后他将 D D D除以这个数字得到新的 D D D。他重复这个过程直到 D D D变为 1 1 1。请问给你一个 n n n n n n变为 1 1 1所需的操作次数是多少?

输入

输入以整数 T ( 10000 ) T(10000) T10000开始,表示测试用例的数量。

每种情况都以整数 n ( 1 到 n 到 105 ) n(1到n到105) n1n105开始。


输出

对于每个输入案例,您必须输出案例编号和预期值。小于 1 0 − 6 10^{-6} 106的错误将被忽略。

动态规划

d p [ i ] dp[i] dp[i]表示从 i i i 1 1 1所需要的次数。
则可以列出方程:
d p [ i ] = d p [ 1 ] + d p [ 2 ] + ⋯ + d p [ i ] n + 1 dp[i] = \frac{dp[1]+dp[2]+\cdots+dp[i]}{n}+1 dp[i]=ndp[1]+dp[2]++dp[i]+1

d p [ i ] dp[i] dp[i]移到左边,化简后得:
d p [ i ] = d p [ 1 ] + d p [ 2 ] + ⋯ + d p [ i − 1 ] + n n − 1 dp[i]=\frac{dp[1]+dp[2]+\cdots+dp[i-1]+n}{n-1} dp[i]=n1dp[1]+dp[2]++dp[i1]+n

代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <cstring>
#include <cmath>
#define maxn 100005
using namespace std;

double dp[maxn];
int a[maxn];
int n;
vector<int> G[maxn];

int main(){
//    freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false);
    int T, _max = 0;
    cin >> T;

    for(int i = 1; i <= T; i++){
        cin >> a[i];
        _max = max(_max, a[i]);
    }

    for(int i = 2; i <= _max; i++){
        for(int j = 1; j <= sqrt(i); j++){
            if(i % j == 0){
                G[i].push_back(j);
                if(j * j != i) G[i].push_back(i / j);
            }
        }
    }

    for(int i = 2; i <= _max; i++){
        int num = G[i].size();
        for(int j = 0; j < num; j++){
            if(G[i][j] != i) dp[i] += dp[G[i][j]];
        }
        dp[i] = (dp[i] + num) / (num - 1);
    }

    for(int cas = 1; cas <= T; cas++){
        printf("Case %d: %lf\n", cas, dp[a[cas]]);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值