未完待续...

Race to 1 Again

题目大意

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.

 给你一个整数,每一次操作可以除以包括当前这个数在内的一个因子,除以每个数都是等概率的,问将n变为1的期望步数

测试数据有多组

\(1 ≤ N ≤ 10^5\)

题解

如果将\(dp[i]\)视为当当前值为\(i\)时,将i变为1的期望步数, 很容易就可以想到一个递推式子

\(dp[1]=0\)
\(Ans=dp[n]\)
\(dp[i]=\frac{dp[p_1] + dp[p_2] + dp[p_3] + ... + dp[i]}{cnt}\)
其中p为i的所有因子,cnt为因子的个数

但是由于在这个式子中,dp[i]可以被他自己给转移,所以我们肯定不能用这个式子来求最终的答案

不难想到,可以通过将\(dp[i]\)移到等号的同一边来化简式子

\(cnt*dp[i]=dp[p_1] + dp[p_2]+...+dp[p_{cnt-1}]+dp[i]\)
\((cnt - 1)*dp[i]=dp[p_1] + dp[p_2]+...+dp[p_{cnt-1}]\)
\(dp[i]=\frac{dp[p_1] + dp[p_2]+...+dp[p_{cnt-1}]}{cnt - 1}\)

于是,我们就可以用一个递推来愉快的来求答案了

时间复杂度\(O(n\sqrt{n})\)

代码

#include <cstdio>
#include <cmath>

const int N = 1e5;

int n, kase;
double dp[N + 10];

int main() {
// 先预处理答案
dp[1] = 0;
for (int i = 2; i <= N; i ++) {
double x = 0;
int cnt = 0;
for (int j = 1; j <= sqrt(i); j ++) if (i % j == 0) {
++ cnt, x += dp[j];
if (i / j != j) ++ cnt, x += dp[i / j];
}
dp[i] = (x + cnt) / ((cnt - 1) * 1.0);
}

// 多组测试数据
int T; scanf("%d", &T);
while (T --) {
scanf("%d", &n);
printf("Case %d: %.7lf\n", ++ kase, dp[n]);
}
return 0;
}


注意点

  • n的因子包括1和他本身
Collecting Bugs

代码

#include <cstdio>

const int N = 1000;

int n, s;
double dp[N + 10][N + 10];

int main() {
scanf("%d%d", &n, &s);
double p0 = n * s;
for (int i = n; i >= 0; i --) {
for (int j = s; j >= 0; j --) if (i != n || j != s) {
dp[i][j] = (double) (dp[i][j + 1] * i * 1.0 / n * (1 - j * 1.0 / s)
+ dp[i + 1][j] * (1 - i * 1.0 / n) * j * 1.0 / s
+ dp[i + 1][j + 1] * (1 - i * 1.0 / n) * (1 - j * 1.0 / s) + 1) / (1 - i * j / p0);
}
}
printf("%.4lf\n", dp[0][0]);
return 0;
}


注意点

  • 由于是poj的题,且poj的g++不支持使用%lf,所以如果你使用了%lf来输出,必须要提交到c++里
One Person Game

代码

#include <cstdio>
#include <cstring>

const int N = 500;

double a[N * 2], b[N * 2], p[100];
int n, k1, k2, k3, x, y, z;

int main() {
int T; scanf("%d", &T);
while (T --) {
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
memset(p, 0, sizeof(p));
scanf("%d%d%d%d%d%d%d", &n, &k1, &k2, &k3, &x, &y, &z);

p[0] = 1.0 / (k1 * k2 * k3);
for (int i = 1; i <= k1; i ++) for (int j = 1; j <= k2; j ++) for (int k = 1; k <= k3; k ++)
if (i != x || j != y || k != z)
p[i + j + k] += p[0];

for (int i = n; i >= 0; i --) {
for (int j = 3; j <= k1 + k2 + k3; j ++) {
a[i] += a[i + j] * p[j];
b[i] += b[i + j] * p[j];
}
a[i] += p[0];
b[i] += 1;
}

printf("%.9lf\n", b[0] / (1 - a[0]));
}
return 0;
}


Check the difficulty of problems

代码

#include <cstdio>
#include <cstring>

const int T = 1001;
const int M = 31;

int m, t, n;
double dp[T][M][M], p[T][M];

int main() {
while (scanf("%d%d%d", &m, &t, &n) && m && t && n) {
memset(dp, 0, sizeof(dp));

for (int i = 1; i <= t; i ++) for (int j = 1; j <= m; j ++) scanf("%lf", &p[i][j]);
for (int i = 1; i <= t; i ++) dp[i][0][0] = 1;

for (int i = 1; i <= t; i ++) {
for (int j = 1; j <= m; j ++) {
for (int k = 0; k <= j; k ++) {
if (k > 0) dp[i][j][k] += dp[i][j - 1][k - 1] * p[i][j];
if (k < j) dp[i][j][k] += dp[i][j - 1][k] * (1 - p[i][j]);
}
}
}

double p1 = 1, p2 = 1;
for (int i = 1; i <= t; i ++) {
p1 *= 1 - dp[i][m][0];

double tmp = 0;
for (int j = 1; j < n; j ++) tmp += dp[i][m][j];
p2 *= tmp;
}
printf("%.3lf\n", p1 - p2);
}
return 0;
}


注意点

  • 由于是poj的题,且poj的g++不支持使用%lf,所以如果你使用了%lf来输出,必须要提交到c++里
Bag of mice

代码

#include <cstdio>

const int N = 1000;

int w, b;
double dp[N + 10][N + 10];

int main() {
scanf("%d%d", &w, &b);
for (int i = 1; i <= w; i ++) dp[i][0] = 1;
for (int i = 1; i <= w; i ++) {
for (int j = 1; j <= b; j ++) {
dp[i][j] = i * 1.0 / (i + j);

double k = j * 1.0 / (i + j) * (j - 1) / (i + j - 1);
if (i >= 1 && j >= 2) {
dp[i][j] += dp[i - 1][j - 2] * k * i * 1.0 / (i + j - 2);
}
if (j >= 3) {
dp[i][j] += dp[i][j - 3] * k * (j - 2) * 1.0 / (i + j - 2);
}
}
}
printf("%.9lf\n", dp[w][b]);
return 0;
}


Journey

代码

#include <cstdio>

const int N = 100000;

int n, head[N + 10], nxt[N * 2 + 10], to[N * 2 + 10], tot, v[N + 10];
double d[N + 10];
void add(int x, int y) {
nxt[++ tot] = head[x];
head[x] = tot;
to[tot] = y;
}

void dfs(int x, int l) {
v[x] = true;
int cnt = 0;
double k = 0;
for (int i = head[x]; i; i = nxt[i]) {
int y = to[i];
if (v[y]) continue;
dfs(y, l + 1);
++ cnt;
k += d[y];
}
if (cnt == 0) {
d[x] = l;
} else {
d[x] = 1.0 / cnt * k;
}
}

int main() {
scanf("%d", &n);
for (int i = 1; i < n; i ++) {
int x, y; scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
dfs(1, 0);
printf("%.8lf", d[1]);
return 0;
}