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
Output
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) T(10000)开始,表示测试用例的数量。
每种情况都以整数
n
(
1
到
n
到
105
)
n(1到n到105)
n(1到n到105)开始。
输出
对于每个输入案例,您必须输出案例编号和预期值。小于 1 0 − 6 10^{-6} 10−6的错误将被忽略。
动态规划
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]=n−1dp[1]+dp[2]+⋯+dp[i−1]+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;
}