CodeForces - 1730B Meeting on the Line

CodeForces - 1730B Meeting on the Line

题解:思维,找货舱位置/二分答案

首先直接来引理,假设现在一个数轴上有许多点,那么一个点到这些点距离最短之和的点肯定在数轴最左端点和最右端点的中间\((x_{max}+x_{min})/2\)

知道引理后我们直接来看题目,但是题目这边又给出了,每个人需要时间t来换衣服,这该怎么解决,我们可以这么思考,我们能不能把换衣服的时间假想成这个人在正式出发之前,他改变了自己的位置,就比如它可以利用t的时间往它的右边走,使其坐标变成\(x_i+t_i\),也可以往他的左边走\(x_i-t_i\),那么问题就又变成引理了

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define all(x) (x).begin(), (x).end()
#define endl '\n'
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 2e5 + 10;
int n;
ll a[N];
ll b[N];
int main(void)
{
    Zeoy;
    int t = 1;
    cin >> t;
    while (t--)
    {
        cin >> n;
        for (int i = 1; i <= n; ++i)
            cin >> a[i];
        for (int i = 1; i <= n; ++i)
        {
            cin >> b[i];
        }
        ll l = INF, r = -INF;
        for (int i = 1; i <= n; ++i)
        {
            l = min(l, a[i] - b[i]);
            r = max(r, a[i] + b[i]);
        }
        cout << fixed << setprecision(10) << 1.0 * (l + r) / 2 << endl;//注意输出精度
    }
    return 0;
}

二分的做法:

这道题我们该怎么二分答案?到底是二分时间还是二分距离?我们经过模拟,发现如果我们去关注位置,我们得到的答案是没有线性关系的,根本没有二分性,所以选择二分时间。

那么二分时间的话有两个关键点:

1.我们的check函数怎么写?

​ 我们需要判断现在我二分出来的答案合法性,就是需要判断所有人在去掉它换装的时间t后,他所能够到达的位置是一个区间,我们只需要判断所有区间有没有公共的交集,当然,如果他换装的时间t>=mid,说明这个人都没有出发,答案肯定不合法,那么我们怎么去判断所有区间有没有公共交集?我们只需要去判断区间左端点的最大值和区间右端点的最小值的关系即可,如果\(l_{max}<=r_{min}\)就代表答案合法,说明大家在答案mid的时间段内,所有人都能汇聚在一个点,都能相遇

2.ans怎么记录,很简单,如果某个答案合法,我们直接记录\(ans=\frac{l_{max}+r_{min}}{2}\)即可

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define all(x) (x).begin(), (x).end()
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e5 + 10;
double a[N];
double t[N];
int n;
double ans;
bool check(double mid)
{
    double l = -INF, r = INF;
    for (int i = 1; i <= n; ++i)
    {
        if (t[i] >= mid)					//时间不够,都没有出发,答案肯定不合法
            return 0;
        else
        {
            l = max(a[i] - mid + t[i], l);
            r = min(a[i] + mid - t[i], r);
        }
    }
    if (l > r)
        return 0;
    else
    {
        ans = (l + r) / 2;
        return 1;
    }
}
int main(void)
{
    Zeoy;
    int T = 1;
    cin >> T;
    while (T--)
    {
        cin >> n;
        for (int i = 1; i <= n; ++i)
        {
            cin >> a[i];
        }
        for (int i = 1; i <= n; ++i)
        {
            cin >> t[i];
        }
        double l = 0, r = 1e9;
        int cnt = 1000;
        while (cnt--)
        {
            double mid = (l + r) / 2;
            if (check(mid))
                r = mid;
            else
                l = mid;
        }
        cout << fixed << setprecision(10) << ans << endl;	//注意精度
    }
    return 0;
}
posted @ 2023-01-08 13:09  Zeoy_kkk  阅读(30)  评论(0编辑  收藏  举报