[AGC040D] Balance Beam
有一个显而易见的性质, 能追上的起点是一段连续的区间。 那么我们只需要考虑如何才能追上。
以路程为 \(x\) 轴, 时间为 \(y\) 轴, 那 \(Alice\) 到达终点的时间是一定的,设为 \(T\)。 只需要考虑 \(Bob\) 是否能在 \(\leq T\) 的时间内到达终点。
考察一下 \(Bob\) 的 \(y\) 轴的增速,可以发现如果将 \(Bob\) 被 \(Alice\) 追上后的路程合并到 \(Alice\) 上,那么 \(Bob\) 走的就是一段增速为 \(b_i\) 一段增速为 \(a_i\)。
有了这样的 \(insight\) 我们就能得知, \(Bob\) 是走了一段增速为 \(max(b_i, a_i)\) 的路。 (证明: 将最后一段路按照 \(b_i-a_i\) 从大到小排序, 如果 \(Alice\) 能追上 \(Bob\) 那么增速能取到上界。)
路程题可以转换为时间。
贪心题+函数题 可以举例+画图依次来观察性质。
代码
#include<bits/stdc++.h>
#define RG register
#define LL long long
#define U(x, y, z) for(RG int x = y; x <= z; ++x)
#define D(x, y, z) for(RG int x = y; x >= z; --x)
using namespace std;
void read(){}
template<typename _Tp, typename... _Tps>
void read(_Tp &x, _Tps &...Ar) {
x = 0; char ch = getchar(); bool flg = 0;
for (; !isdigit(ch); ch = getchar()) flg |= (ch == '-');
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
if (flg) x = -x;
read(Ar...);
}
inline char Getchar(){ char ch; for (ch = getchar(); !isalpha(ch); ch = getchar()); return ch;}
template <typename T> inline void write(T n){ char ch[60]; bool f = 1; int cnt = 0; if (n < 0) f = 0, n = -n; do{ch[++cnt] = char(n % 10 + 48); n /= 10; }while(n); if (f == 0) putchar('-'); for (; cnt; cnt--) putchar(ch[cnt]);}
template <typename T> inline void writeln(T n){write(n); putchar('\n');}
template <typename T> inline void writesp(T n){write(n); putchar(' ');}
template <typename T> inline void chkmin(T &x, T y){x = x < y ? x : y;}
template <typename T> inline void chkmax(T &x, T y){x = x > y ? x : y;}
template <typename T> inline T Min(T x, T y){return x < y ? x : y;}
template <typename T> inline T Max(T x, T y){return x > y ? x : y;}
inline void readstr(string &s) { s = ""; static char c = getchar(); while (isspace(c)) c = getchar(); while (!isspace(c)) s = s + c, c = getchar();}
inline void FO(string s){freopen((s + ".in").c_str(), "r", stdin); freopen((s + ".out").c_str(), "w", stdout);}
#define int LL
const int N = 1e5 + 10;
#define pii pair<int, int>
#define fi first
#define se second
int n;
pii s[N], t[N];
LL sum[N], tot;
LL ansp = 1 << 30, ansq = 1;
inline void getMin(LL x, LL y)
{
if((__int128)x*ansq<(__int128)y*ansp)
ansp = x, ansq = y;
}
inline LL calc(int x, int mid) {
int tmp = max(s[x].fi, s[x].se);
return t[mid].fi <= tmp ? sum[mid] - tmp : sum[mid];
}
inline int binSearch(int x) {
int l = 1, r = n, res = -1;
while (l <= r) {
int mid = l + r >> 1;
if (calc(x, mid) >= tot - s[x].se)
res = mid, r = mid - 1;
else
l = mid + 1;
}
return res;
}
signed main(){
//FO("");
read(n);
U(i, 1, n) {
read(s[i].fi, s[i].se);
t[i].fi = max(s[i].fi, s[i].se), t[i].se = i;
tot += s[i].fi;
}
sort(t + 1, t + n + 1), reverse(t + 1, t + n + 1);
U(i, 1, n) sum[i] = sum[i - 1] + t[i].fi;
U(i, 1, n) {
int res = binSearch(i);
if (res < 0) continue ;
LL tmp = tot - calc(i, res);
if (t[res].fi <= max(s[i].fi, s[i].se)) res--;
if (tmp < 0) continue ;
getMin((LL) res * s[i].se + tmp, s[i].se);
}
ansq *= n, ansp = ansq - ansp;
if (ansp <= 0) {
puts("0 1");
return 0;
}
LL g = __gcd(ansp, ansq);
writesp(ansp / g), writeln(ansq / g);
return 0;
}