CF 303E Random Ranking
cnblogs。
首先对于浮点数的随机,可以忽略
如果知道了
那么如果知道了
不过现在的问题是
发现其实
于是这启发对
不过这样做在最后会遇到求
此时考虑另外一个想法,不去考虑分析
不过这就有问题了,如果一个数的值
有以下结论:若有
感性理解一下,因为不用考虑相等的关系,就可以当作是随机一个排列代表这
于是考虑枚举
转移直接暴力枚举这一个数的三种情况即可,可以做到
要做到更优,可以考虑缺一分治,可以参考这篇题解做到
有一个想法是通过背包撤销做到
我的代码是
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
constexpr double eps = 1e-9;
constexpr int maxn = 80;
int n, m;
int l[maxn], r[maxn], val[maxn * 2];
double low[maxn], eq[maxn], upp[maxn];
double f[maxn][maxn];
double ans[maxn][maxn];
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d%d", &l[i], &r[i]);
val[i << 1] = l[i], val[i << 1 | 1] = r[i];
}
std::sort(val, val + n * 2);
m = std::unique(val, val + n * 2) - val;
for (int s = 0; s + 1 < m; s++) {
const int sl = val[s], sr = val[s + 1];
for (int i = 0; i < n; i++) {
if (l[i] <= sl && sr <= r[i]) {
low[i] = 1.0 * (sl - l[i]) / (r[i] - l[i]);
eq[i] = 1.0 * (sr - sl) / (r[i] - l[i]);
upp[i] = 1.0 * (r[i] - sr) / (r[i] - l[i]);
} else if (r[i] <= sl) {
low[i] = 1.0, eq[i] = upp[i] = 0.0;
} else {
upp[i] = 1.0, eq[i] = low[i] = 0.0;
}
}
for (int u = 0; u < n; u++) {
if (eq[u] < eps) continue;
for (int x = 0; x < n; x++) {
for (int y = 0; x + y < n; y++) f[x][y] = 0.0;
}
f[0][0] = eq[u];
for (int i = 0, lim = 0; i < n; i++) {
if (u == i) continue;
lim++;
if (upp[i] > 1 - eps) continue;
if (low[i] > 1 - eps) {
for (int x = lim; x >= 0; x--) {
for (int y = 0; x + y <= lim; y++) {
f[x][y] = x ? f[x - 1][y] : 0.0;
}
}
continue;
}
for (int x = lim; x >= 0; x--) {
for (int y = lim - x; y >= 0; y--) {
f[x][y] *= upp[i];
if (x) f[x][y] += f[x - 1][y] * low[i];
if (y) f[x][y] += f[x][y - 1] * eq[i];
}
}
}
for (int x = 0; x < n; x++) {
for (int y = 0; x + y < n; y++) {
const double prob = f[x][y] / (y + 1);
ans[u][x] += prob, x + y + 1 < n && (ans[u][x + y + 1] -= prob, 1);
}
}
}
}
for (int i = 0; i < n; i++) {
printf("%.10lf ", ans[i][0]);
for (int j = 1; j < n; j++) {
printf("%.10lf ", ans[i][j] += ans[i][j - 1]);
}
puts("");
}
return 0;
}