前言
人类智慧,不可思议。
解析
考虑画出两个人的 S−TS-TS−T 折线图,那么答案如何表示?
可以理解成把 BBB 的图像不断下移,直到与 AAA 的图像只剩一个交点,此时在 xxx 轴的截矩就是答案。
设平移后 BBB 图像与 xxx 轴交于 kkk 点,观察 kkk 右侧的折线,发现由于 xxx 轴下方的 BBB 图像不知道,BBB 折线最后到达的位置是未知的。
但是我们可以观察到,AAA 折线最后必然会到达 (n,∑ai)(n,\sum a_i)(n,∑ai) 的位置,并且又由于 A,BA,BA,B 折线有交点,不妨考虑从 BBB 折线到交点后转到 AAA 折线的这段图像。
我们肯定要最小化这段的横向距离,那么肯定就要让这段图像的斜率尽可能大,一个显然的斜率上界是 max(ai,bi)\max (a_i,b_i)max(ai,bi),并且只要按照 bi−aib_i-a_ibi−ai 降序排序,这个上界就可以取到。
那么按照 max(ai,bi)max(a_i,b_i)max(ai,bi) 升序排序,考虑枚举 kkk 点所在的线段 ppp,那么我们必然取得是一段后缀使得 bp+∑i=posnmax(ai,bi)≥∑aib_p+\sum_{i=pos}^n\max(a_i,b_i)\ge \sum a_ibp+∑i=posnmax(ai,bi)≥∑ai,再加上 ppp 内部的长度即可。
二分找一下就好了,时间复杂度 O(nlogn)O(n\log n)O(nlogn)。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("line: %d\n",__LINE__)
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}const int N=2e5+100;
int Flag=0;bool mem1;int n;struct frac{ll x,y;// x/y;frac(int X=0,int Y=1){int g=__gcd(X,Y);x=X/g;y=Y/g;}
};
bool operator < (const frac &a,const frac &b){return (__int128)a.x*b.y<(__int128)b.x*a.y;
}struct node{int a,b;
}p[N];
ll sum[N];bool mem2;
signed main(){#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endif//debug("mem=%lf\n",abs(&mem2-&mem1)/1024./1024);ll sa(0);n=read();for(int i=1;i<=n;i++){p[i].a=read();p[i].b=read();sa+=p[i].a;}sort(p+1,p+1+n,[&](node u,node v){return max(u.a,u.b)<max(v.a,v.b);});for(int i=1;i<=n;i++) sum[i]=sum[i-1]+max(p[i].a,p[i].b);frac ans(0,1);for(int i=1;i<=n;i++){int st=0,ed=n+1;while(st<ed){int mid=(st+ed+1)>>1;if(sum[n]-sum[mid-1]-(mid<=i)*max(p[i].b,p[i].a)+p[i].b>=sa) st=mid;else ed=mid-1;}if(!st) continue; frac res(sum[n]-sum[st-1]-(st<=i)*max(p[i].b,p[i].a)+p[i].b-sa,p[i].b);if(res.x>res.y) continue;res.x+=res.y*(st-1-(i<st));if(ans<res) ans=res;}ll g=__gcd(1ll*n,ans.x);ans.x/=g;ans.y*=n/g;printf("%lld %lld\n",ans.x,ans.y);return 0;
}