[Gym-101482] G - Gathering(三分套三分+前綴和)

題意

2維平面給n個整點, 找出一個整點(x,y)使得這個整點到其他n個點的曼哈頓距離和最小,同時需要滿足每個點到這個(x,y)的曼哈頓距離不超過d.
n1e5,0xi,yi1e9,0d2e9n\le 1e5, 0 \le x_i, y_i \le 1e9, 0 \le d \le 2e9

解題思路

如果沒有"每個點到這個(x,y)的曼哈頓距離不超過d."的限制,則易得(x的中位數,y的中位數)是最優點.
考慮限制,我們發現每個點都有一個菱形的可選區域,這n個菱形的可選區域的交集就是我們可以選擇的區域. 這個區域其實可以看成4條直線框起來的區域,那麼我們維護這4條直線就可以得到合法區域.
注意到,當x確定的時候,答案關於y的函數是一個凹函數, 同樣的, 當x變化的時候, y作爲每個x的最優選取位置,則答案關於x的函數也是一個凹函數,所以三分套三分就做完了.
在求答案的時候,可以利用二分+前綴和快速得到n個點到指定點的曼哈頓距離和.

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define fors(i, a, b) for(int i = (a); i < (b); ++i)
#define P pair<int,int>
using namespace std;
const int maxn = 1e5 + 50;
const ll inf = 0x3f3f3f3f3f3f3f3f;
int n;
ll xsum[maxn], ysum[maxn];
ll x[maxn], y[maxn];
ll d;
ll L = -inf, R = inf;//x-y
ll D = -inf, U = inf;//x+y
ll f(ll a, ll b[], ll c[]){
    if(a > b[n]){
        return (ll)n*a - c[n];
    }else if(a < b[0]){
        return c[n]-n*a;
    }else{
        int p = lower_bound(b+1, b+1+n, a)-b;
        return (c[n] - c[p-1] - (ll)(n-p+1)*a) + (ll)(p-1)*a - c[p-1];
    }
}
bool in(int x, int y){
    ll t1 = x-y;
    ll t2 = x+y;
    //cout<<"L:"<<L<<" R:"<<R<<" D:"<<D<<" U:"<<U<<endl;
    return L<=t1 && t1 <= R && D <= t2 && t2 <= U;
}
ll sol(ll a){
    ll l = max(a-R, D-a);
    ll r = min(a-L, U-a);
    if(r < l) return inf;
    ll ans = inf;
    while(r-l >= 3){
        ll lmid = l + (r-l)/3;
        ll rmid = r - (r-l)/3;
        ll la = f(lmid, y, ysum), ra = f(rmid, y, ysum);
        if(la >= ra) ans = min(ra, ans), l = lmid;
        else ans = min(ans, la), r = rmid;
    }
    while(l <= r) ans = min(ans, f(l, y, ysum)), l++;
    return ans;
}
int main()
{
    scanf("%d", &n);
    fors(i, 1, n+1) {
        scanf("%lld%lld", &x[i], &y[i]);
    }
    cin>>d;
    fors(i, 1, n+1){
        L = max(L, x[i] - y[i]-d);
        R = min(R, x[i] - y[i]+d);
        D = max(D, x[i] + y[i]-d);
        U = min(U, x[i] + y[i]+d);
    }
    sort(x+1, x+1+n); sort(y+1, y+1+n);
    fors(i, 1, n+1) xsum[i] = xsum[i-1] + x[i], ysum[i] = ysum[i-1] + y[i];
    if(in(x[n/2], y[n/2])){
        cout<<f(x[(n+1)/2], x, xsum)+f(y[(n+1)/2], y, ysum)<<endl;
    }else if(U < D || R < L){
        printf("impossible\n");
    }else {
        ll ans = inf;
        ll l = (D+L+1)/2;
        ll r = (R+U)/2;
        //cout<<"l:"<<l<<" r:"<<r<<endl;
        while(r-l >= 3){
            ll lmid = l + (r-l)/3;
            ll rmid = r - (r-l)/3;
            ll la = sol(lmid) + f(lmid, x, xsum);
            ll ra = sol(rmid) + f(rmid, x, xsum);
            if(la >= ra) ans = min(ans, ra), l = lmid;
            else ans = min(ans, la), r = rmid;
        }
        while(l <= r) ans = min(ans, sol(l)+f(l, x, xsum)), l++;
        cout<<ans<<endl;
    }
}
/*
5
3 1
4 1
5 9
2 6
5 3
4

*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章