[Gym-101482] G-Gathering(3ポイントの3ポイントセット+プレフィックス合計)

題名

2次元平面はn個の積分点を与え、この積分点から他のn個の点までのマンハッタン距離が最小になるように積分点(x、y)を見つけ、各点からこれ(x、y)までのマンハッタン距離を満たす必要がありますないよりdより
N≤1 E 5、0≤XI、YI≤1つのE 9、0≤D≤2電子9のn \ル1E5、0 \ルX_I、Y_I \ル1E9、0 \ルD \ル2E91 e 5 0バツそして1 e 9 0d2 e 9

問題解決のアイデア

「各ポイントからこの(x、y)までのマンハッタン距離がdを超えない」という制限がない場合、簡単にアクセスできる(xの中央値、yの中央値)が最適なポイントです。
制限を考慮すると、各ポイントには、ひし形のオプション領域があります。n個のひし形のオプション領域の交点が、選択できる領域です。この領域は、実際には4つの直線で囲まれた領域と見なすことができます。有効な領域を取得できます
。xが決定されると、yに対する解の関数は凹関数になります。同様に、xが変化すると、各xの最適な選択位置としてyが使用され、解はxの関数になりますこれも凹関数なので、3点の3点セットが実行されます。
答えを探すときは、2点+接頭辞の合計を使用して、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

*/

おすすめ

転載: blog.csdn.net/qq_43202683/article/details/105631998