题解:P12297 [ICPC 2022/2023 WF] 三种骰子
骰子
我们只说第一个问题,第二个问题是一样的。
现在的问题变成,给每一个
第一,也是官方题解的做法。我们将一对数
第二种,既然是求最小平均数,我们可以考虑二分答案。假设当前二分的平均数为
如果存在
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const double eps = 1e-10, inf = 1e16;
const int N = 6e5 + 5;
int n, m, lsh[N], cnt, suma[N], sumb[N];
double x[N], y[N];
struct node {
double x, y;
} arr[N];
bool checkA(double mid) {
double fl0 = inf, fl1 = 0;
for (int i = 1; i <= cnt; i++) {
arr[i].x = x[i] - 0.5, arr[i].y = y[i] - mid;
if (arr[i].x >= 0 && arr[i].y <= 0)
return true;
else if (arr[i].x <= 0 && arr[i].y < 0)
fl0 = min(fl0, arr[i].x / arr[i].y);
else if (arr[i].x >= 0 && arr[i].y > 0)
fl1 = max(fl1, arr[i].x / arr[i].y);
}
return fl0 < fl1;
}
bool checkB(double mid) {
double fl0 = inf, fl1 = 0;
for (int i = 1; i <= cnt; i++) {
arr[i].x = x[i] - mid, arr[i].y = y[i] - 0.5;
if (arr[i].x >= 0 && arr[i].y <= 0)
return true;
else if (arr[i].x <= 0 && arr[i].y < 0)
fl0 = min(fl0, arr[i].x / arr[i].y);
else if (arr[i].x >= 0 && arr[i].y > 0)
fl1 = max(fl1, arr[i].x / arr[i].y);
}
return fl0 < fl1;
}
int main() {
#ifdef ddxrS
freopen("sample.in", "r", stdin);
freopen("sample.out", "w", stdout);
#else
freopen("dice.in", "r", stdin);
freopen("dice.out", "w", stdout);
#endif
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
vector<int> a(n);
for (auto &p : a) {
cin >> p;
lsh[++cnt] = p, lsh[++cnt] = p + 1;
if (p > 1)
lsh[++cnt] = p - 1;
}
cin >> m;
vector<int> b(m);
for (auto &p : b) {
cin >> p;
lsh[++cnt] = p, lsh[++cnt] = p + 1;
if (p > 1)
lsh[++cnt] = p - 1;
}
sort(lsh + 1, lsh + cnt + 1);
cnt = unique(lsh + 1, lsh + cnt + 1) - lsh - 1;
for (auto &p : a) p = lower_bound(lsh + 1, lsh + cnt + 1, p) - lsh, suma[p]++;
for (int i = 1; i <= cnt; i++) suma[i] += suma[i - 1];
double sum = 0;
for (auto &p : b) {
p = lower_bound(lsh + 1, lsh + cnt + 1, p) - lsh, sumb[p]++;
sum += suma[p - 1] + (suma[p] - suma[p - 1]) / 2.0;
}
for (int i = 1; i <= cnt; i++) sumb[i] += sumb[i - 1];
sum = sum / m / n;//不要写成 sum /= n * m, n * m 爆 int 了。
if (sum > 0.5) {
swap(n, m), swap(a, b);
for (int i = 1; i <= cnt; i++) swap(suma[i], sumb[i]);
}
for (int i = 1; i <= cnt; i++) {
x[i] = (suma[i - 1] + (suma[i] - suma[i - 1]) / 2.0) / n;
y[i] = (sumb[i - 1] + (sumb[i] - sumb[i - 1]) / 2.0) / m;
}
double l = 0, r = 1, mid, ansA = 0, ansB = 0;
while (r - l > 1e-10) {
mid = (l + r) / 2;
if (checkA(mid))
r = mid + eps, ansA = mid;
else
l = mid - eps;
}
l = 0, r = 1;
while (l < r - eps) {
mid = (l + r) / 2;
if (checkB(mid))
l = mid + eps, ansB = mid;
else
r = mid - eps;
}
cout << fixed << setprecision(12) << ansA << ' ' << ansB << '\n';
return 0;
}