「Light OJ1038」Race to 1 Again【期望dp】

本文探讨了一道数学与编程结合的问题,即对于任意正整数N,通过不断选择其因子进行除法操作,直至变为1,求达到目标状态的平均操作次数。文章详细解析了解题思路,采用动态规划方法,并通过实例计算,提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1038 - Race to 1 Again

Time Limit: 2 second(s) Memory Limit: 32 MB

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

In each turn he randomly chooses a divisor of DDD (111 to DDD). Then he divides DDD by the number to obtain new DDD. He repeats this procedure until DDD becomes 111. What is the expected number of moves required for NNN to become 111.

Input

Input starts with an integer T(≤10000)T (\leq 10000)T(10000), denoting the number of test cases.

Each case begins with an integer N(1≤N≤105)N (1 \leq N \leq 10^5)N(1N105).

Output

For each case of input you have to print the case number and the expected value. Errors less than 10−610^{-6}106 will be ignored.

Sample Input

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

题意

  • 给你一个整数,每次操作可以选一个nnn的正因子并除以这个因子,求这个数第一次变成111的期望操作数

解法

  • dp[i]dp[i]dp[i]表示n=in=in=i时对应的答案
  • 我们知道,期望是试验中每次可能结果的概率乘以其结果的总和,对应于本题中,dp[i]=∑所有使i变成1的操作方案选择此方案对应的概率×此方案的操作数dp[i]=\sum^{所有使i变成1的操作方案}{选择此方案对应的概率\times此方案的操作数}dp[i]=使i1×
    • 首先说明dp[2]=2dp[2]=2dp[2]=2分以下情况讨论
      • 第一步选择2的因子222,那么nnn直接变成111,结束操作,这种方案对期望的贡献是T1=12×1T_1=\frac{1}{2}\times 1T1=21×1
      • 第一步选择因子111,那么如果后面继续选择111nnn是保持222不变的,直到选择222,那么显然这种方案下对应的方案是无穷多种的,其贡献
        T2=lim⁡n→∞(12)1×12×2+(12)2×12×3+...+(12)n×12×(n+1)T22=lim⁡n→∞(12)2×12×2+(12)3×12×3+...+(12)n+1×12×(n+1)相减,得T22=lim⁡n→∞(12)1×12×2+(12)2×12+...+(12)n×12−(12)n+1×12×(n+1)=12+lim⁡n→∞(12)2×12+...+(12)n×12=12+lim⁡n→∞12×14×(1−(12)n−1)1−12=0.75T2=1.5\begin{aligned}T_2 &= \lim_{n\rightarrow \infty}^{}{\left(\frac{1}{2}\right)^1\times\frac{1}{2}\times2+\left(\frac{1}{2}\right)^2\times\frac{1}{2}\times3+...+\left(\frac{1}{2} \right)^n\times\frac{1}{2}\times (n+1)} \\ \frac{T_2}{2} &= \lim_{n\rightarrow \infty}^{}{\left(\frac{1}{2}\right)^2\times\frac{1}{2}\times2+\left(\frac{1}{2}\right)^3\times\frac{1}{2}\times3+...+\left(\frac{1}{2} \right)^{n+1}\times\frac{1}{2}\times (n+1)} \\ 相减,得 \\ \frac{T_2}{2}&=\lim_{n\rightarrow \infty} \left(\frac{1}{2}\right)^1\times\frac{1}{2}\times2+ \left(\frac{1}{2}\right)^2\times\frac{1}{2}+...+ \left(\frac{1}{2}\right)^n\times\frac{1}{2}-\left(\frac{1}{2} \right)^{n+1}\times\frac{1}{2}\times (n+1) \\ &=\frac{1}{2}+\lim_{n\rightarrow \infty} \left(\frac{1}{2}\right)^2\times\frac{1}{2}+...+ \left(\frac{1}{2}\right)^n\times\frac{1}{2}\\ &=\frac{1}{2}+\lim_{n\rightarrow \infty} \frac{1}{2}\times \frac{\frac{1}{4}\times(1-(\frac{1}{2})^{n-1})}{1-\frac{1}{2}}\\ &=0.75\\ T_2&=1.5 \end{aligned}T22T22T2T2=nlim(21)1×21×2+(21)2×21×3+...+(21)n×21×(n+1)=nlim(21)2×21×2+(21)3×21×3+...+(21)n+1×21×(n+1)=nlim(21)1×21×2+(21)2×21+...+(21)n×21(21)n+1×21×(n+1)=21+nlim(21)2×21+...+(21)n×21=21+nlim21×12141×(1(21)n1)=0.75=1.5
      • 所以dp[2]=T1+T2=2dp[2]=T_1+T_2=2dp[2]=T1+T2=2
    • 然后就可以在可以递推了
      • 定义num[i]num[i]num[i]表示iii的因子个数,fac[i][j]fac[i][j]fac[i][j]表示iii的第jjj个因子
        dp[i]=∑j=1num[i]1num[i]×(dp[fac[i][j]]+1)dp[i]=\sum_{j=1}^{num[i]}{\frac{1}{num[i]}\times(dp[fac[i][j]]+1)}dp[i]=j=1num[i]num[i]1×(dp[fac[i][j]]+1)
        需要注意由于计算dp[i]dp[i]dp[i]的时候需要用到dp[i]dp[i]dp[i],而dp[i]dp[i]dp[i]未求出,可以把右边的包含因子iii的项移到左边,然后再计算dp[i]dp[i]dp[i],相当于解一个一元一次方程

附代码

#include<bits/stdc++.h>

using namespace std;
const int maxn=1e5+10;

double dp[maxn];

int main()
{
    dp[1]=0,dp[2]=2.0;
    for(int i=3;i<maxn;i++){
        int num=0;
        for(int j=1;j*j<=i;j++){
            if(i%j==0){
                num++;
                if(j*j!=i) num++;
            }
        }
        dp[i]=num*1.0/(num-1);
        for(int j=1;j*j<=i;j++){
            if(i%j==0){
                dp[i]+=dp[j]/(num-1);
                if(j!=1&&j*j!=i) dp[i]+=dp[i/j]/(num-1);
            }
        }
    }
    int t;scanf("%d",&t);
    for(int i=1,n;i<=t;i++){
        scanf("%d",&n);
        printf("Case %d: %.10lf\n",i,dp[n]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值