牛客挑战赛43. C.最优公式 (二分,思维,切比雪夫距离与曼哈顿距离的转换)

题目:传送门

题意

 思路

有两种做法:

一.盲猜 a = b,那就直接二分 a,就完事儿了.

二.按照题解那样的思路,这个会比较难想一点吧。

#include <bits/stdc++.h>
#define LL long long
#define ULL unsigned long long
#define UI unsigned int
#define mem(i, j) memset(i, j, sizeof(i))
#define rep(i, j, k) for(int i = j; i <= k; i++)
#define dep(i, j, k) for(int i = k; i >= j; i--)
#define pb push_back
#define make make_pair
#define INF 0x3f3f3f3f
#define inf LLONG_MAX
#define PI acos(-1)
#define fir first
#define sec second
#define lb(x) ((x) & (-(x)))
#define dbg(x) cout<<#x<<" = "<<x<<endl;
using namespace std;
 
const int N = 1e6 + 5;
 
const LL mod = 1e9 + 7;
 
int n, a[N];
 
LL cal(int x) {
 
    int L = 1, R = 1, cnt = 1;
 
    while(L <= n && a[L] < x) L++;
 
    R = L; L--;
 
    LL ans = 0LL, now;
 
    while(cnt <= n) {
 
        if(!L) now = a[R] - x, R++;
 
        else if(R > n) now = x - a[L], L--;
 
        else if(x - a[L] < a[R] - x) now = x - a[L], L--;
 
        else now = a[R] - x, R++;
 
        ans += 1LL * (2LL * cnt - 1LL) * now;
 
        cnt++;
 
    }
 
    return ans;
 
}
 
void solve() {
 
    scanf("%d", &n);
 
    rep(i, 1, n) scanf("%d", &a[i]), a[i] *= 2;
 
    sort(a + 1, a + 1 + n);
 
    int l = 2, r = 1000000000;
 
    LL ans = inf;
 
    while(l <= r) {
 
        int mid = (l + r) >> 1;
 
        LL tmp1 = cal(mid), tmp2 = cal(mid + 1);
 
        if(tmp1 > tmp2) {
 
            ans = min(ans, tmp2);
 
            l = mid + 2;
 
        }
 
        else ans = min(ans, tmp1), r = mid - 1;
 
    }
 
    printf("%lld
", ans % mod);
 
}
 
 
int main() {
 
//    int _; scanf("%d", &_);
//    while(_--) solve();
 
    solve();
 
    return 0;
}
法1
#include <bits/stdc++.h>
#define LL long long
#define ULL unsigned long long
#define UI unsigned int
#define mem(i, j) memset(i, j, sizeof(i))
#define rep(i, j, k) for(int i = j; i <= k; i++)
#define dep(i, j, k) for(int i = k; i >= j; i--)
#define pb push_back
#define make make_pair
#define INF 0x3f3f3f3f
#define inf LLONG_MAX
#define PI acos(-1)
#define fir first
#define sec second
#define lb(x) ((x) & (-(x)))
#define dbg(x) cout<<#x<<" = "<<x<<endl;
using namespace std;
 
const int N = 1e6 + 5;
 
const LL mod = 1e9 + 7;
 
int n, a[N];
 
LL pre[N];
 
LL cal1(int x) {
 
    LL ans = 0LL;
 
    int now = n;
 
    rep(i, 1, n) {
 
        while(now > 1 && a[i] + a[now] > x) now--;
 
        if(a[i] + a[now] <= x) ans += now;
 
    }
 
    return ans >= n * 1LL * n / 2LL + 1LL;
 
}
 
LL cal2(int x) {
 
    LL ans = 0LL;
 
    int now = 1;
 
    rep(i, 1, n) {
 
        while(now < n && a[i] - a[now] > x) now++;
 
        if(a[i] - a[now] <= x) ans += (n - now + 1);
 
    }
 
    return ans >= n * 1LL * n / 2LL + 1LL;
 
}
 
void solve() {
 
    scanf("%d", &n);
 
    rep(i, 1, n) scanf("%d", &a[i]);
 
    sort(a + 1, a + 1 + n);
 
    rep(i, 1, n) pre[i] = pre[i - 1] + a[i];
 
    int l = 1, r = 1e9, ans;
 
    while(l <= r) {
 
        int mid = (l + r) >> 1;
 
        if(cal1(mid)) ans = mid, r = mid - 1;
 
        else l = mid + 1;
 
    }
 
    LL res = 0LL;  int pos = n;
 
    rep(i, 1, n) {
 
        while(pos > 1 && a[i] + a[pos] > ans) pos--;
 
        if(a[i] + a[pos] <= ans) {
 
            res += 1LL * pos * ans - pre[pos] - 1LL * pos * a[i];
 
            res += 1LL * (n - pos) * a[i] + (pre[n] - pre[pos]) - 1LL * (n - pos) * ans;
 
        }
 
        else res += 1LL * n * a[i] + pre[n]- 1LL * n * ans;
 
    }
 
    l = -1e9, r = 1e9;
 
    while(l <= r) {
 
        int mid = (l + r) >> 1;
 
        if(cal2(mid)) ans = mid, r = mid - 1;
 
        else l = mid + 1;
 
    }
 
    pos = 1;
 
    rep(i, 1, n) {
 
        while(pos < n && a[i] - a[pos] > ans) pos++;
 
        if(a[i] - a[pos] <= ans) {
 
            res += 1LL * ans * (n - pos + 1) - (a[i] * 1LL * (n - pos + 1) - pre[n] + pre[pos - 1]);
 
            res += 1LL * a[i] * 1LL * (pos - 1) - pre[pos - 1] - 1LL * ans * (pos - 1);
 
        }
 
        else res += 1LL * n * a[i] - pre[n] - 1LL * ans * n;
 
    }
 
    printf("%lld
",res % mod);
 
}
 
 
int main() {
 
//    int _; scanf("%d", &_);
//    while(_--) solve();
 
    solve();
 
    return 0;
}
法2
原文地址:https://www.cnblogs.com/Willems/p/13715528.html