[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;
}
posted @ 2022-11-07 19:45  Southern_Way  阅读(63)  评论(0)    收藏  举报