Race to 1 Again LightOJ - 1038 概率dp详解

https://cn.vjudge.net/problem/LightOJ-1038

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.

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

Input

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

Each case begins with an integer N (1 ≤ N ≤ 105).

Output

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

Sample Input

3
1
2
50

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

题意:给你一个n,n可以变一次变成他的某一个约数,然后在变成他的某个约数,直到变成1,求n变为1的期望次数?

思路:dp[50]=(dp[1]+1)/6+(dp[2]+1)/6+(dp[5]+1)/6+(dp[10]+1)/6+(dp[25]+1)/6+(dp[50]+1)/6;

怎么枚举每个数字的因子呢,可以用(素数)筛法处理。

遍历到i时,将dp[i]求出,然后将dp[i]的值加入到他的 dp[i的倍数] 中,那么当i=50时,怎么求出dp[50]呢。

当前的dp[50]中的值存的是dp[1]+dp[2]+dp[5]+dp[10]+dp[25],在开一个数组a[i]表示当前的dp[i]中装了多少个数字。及a[50]=5;

假设x为要求出的dp[50]的最终概率, 设sum(及当前dp[50]中存的数字)=dp[1]+dp[2]+dp[5]+dp[10]+dp[25],

dp[50]=(dp[1]+1)/6+(dp[2]+1)/6+(dp[5]+1)/6+(dp[10]+1)/6+(dp[25]+1)/6+(dp[50]+1)/6;

那么等式变为x=(dp[1]+dp[2]+dp[5]+dp[10]+dp[25]+x+a[i]+1)/(a[i]+1);

(a[i]+1)*x=(sum+x+a[i]+1)

a[i]*x=(sum+a[i]+1)

x=(sum+a[i]+1)/a[i];

sum的值也就是当前dp[i]中存的值了;所以dp[i]=(dp[i]+a[i]+1)/a[i];( i>1时成立)

代码:(20ms)

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <map>
#include <queue>
#include <math.h>
#include <time.h>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof a)
#define LL long long
#define inf 0x3f3f3f3f
#define y1 ctx_y1
#define x1 ctx_x1
const LL mod=1e9+7;
const int N=1e5+10;
const int M=1e5;
using namespace std;
double dp[N];
int a[N];
int main()
{
    mem(dp,0);
    mem(a,0);
    dp[1]=0;
    for(int i=1;i<=100000;i++)
    {
        if(i!=1) dp[i]=(a[i]+1+dp[i])/a[i];
        for(int j=i*2;j<=100000;j+=i)
        {
            dp[j]+=dp[i];
            a[j]++;
        }
    }
    int t,cas=1;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        printf("Case %d: %.7f\n",cas++,dp[n]);
    }
}



猜你喜欢

转载自blog.csdn.net/xiangaccepted/article/details/80081597