牛客挑战赛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\n", ans % mod); } int main() { // int _; scanf("%d", &_); // while(_--) solve(); solve(); return 0; }
#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\n",res % mod); } int main() { // int _; scanf("%d", &_); // while(_--) solve(); solve(); return 0; }
一步一步,永不停息