AGC040D

(n)个边,长度相同,对于A来说经过某条边需要花(a_i)时间,对于B来说需要花(b_i)时间。

把边排列之后连成一条链,A从左端点开始向右走,B随机在链上某一点(实数域内)出发向右走。

现在要决定这个排列,使得A和B相遇的概率尽量大。

(nle 10^5)


假设排列固定。以位置-时间建系,从原点开始分别画出A和B的图象。然后将B的图象纵向平移,直到再向下平移不可能和A的图象相交为止(刚好相交)。设此时B的图象和x轴的交点为((p,0))。我们希望最大化(p)

有点性质:此时A和B的图象只会在整点相交。因为刚好相交,所以B的图象在所有的位置小于等于A的图象;如果不在整点相交,因为斜率没有发生改变,一定会出现“穿过”的情况。

考虑从((p,0))开始,先走B的图象,在第一次相交处走A的图象。由于终点是((n,S))(设(S=sum a_i)),固定的,于是最大化(p)相当于最大化((p,0))((n,S))的斜率。路径每段的增量至多是(max(a_i,b_i))

枚举((p,0))所对应的边为(k),假设已经决定了排在(k)后面的边的边集。首先要有(b_k+sum_{后面的i} max(a_i,b_i)ge S)。将(b_i>a_i)的放前面,其它的放后面,以下说明这样就达到了上限。

这样排列之后,在(b_i>a_i)的段中,A和B的相对位移不断减少。所以在(b_i)(a_i)大小关系转变的那一刻,A和B的相对位移达到极值。因为A和B图象恰好相交(于是相对位移大于等于(0)),所以达到极值的那一刻,两者相交。此时就会从走B的图象走到A的图象。

又因为前面(b_i>a_i),贡献(b_i=max(a_i,b_i)),后面类似,所以达到上限。

既然我们希望最大化((p,0))((n,S))的斜率,那么这个边集就可以贪心取,按照(max(a_i,b_i))从大到小排序,找到最小前缀满足(b_k+sum_{i} max(a_i,b_i)ge S)。于是(lceil p ceil)就已经确定了,小数部分进一步算一下即可。

注意:如果二分出来得到(sum_i max(a_i,b_i)> S),则不能算入答案。因为此时不管怎样从((p,0))出发都能到达大于((n,S))的地方。


using namespace std;
#include <bits/stdc++.h>
#define N 100005
#define ll long long
#define db long double
ll gcd(ll a,ll b){
	ll k;
	while (b)
		k=a%b,a=b,b=k;
	return a;
}
int n;
struct info{int a,b;} d[N];
bool cmpd(info x,info y){return max(x.a,x.b)>max(y.a,y.b);}
ll ps[N],sa;
struct frac{
	ll u,v;
	frac(ll _u=0,ll _v=0){u=_u,v=_v;}
	void adj(){
		ll g=gcd(u,v);
		u/=g,v/=g;
	}
};
bool operator<(frac x,frac y){
	return (db)x.u*y.v<(db)y.u*x.v;
}
int main(){
	//freopen("in.txt","r",stdin);
	scanf("%d",&n);
	for (int i=1;i<=n;++i){
		scanf("%d%d",&d[i].a,&d[i].b);
		sa+=d[i].a;	
	}
	sort(d+1,d+n+1,cmpd);
	for (int i=1;i<=n;++i)
		ps[i]=ps[i-1]+max(d[i].a,d[i].b);
	frac ans(0,1);
	for (int k=1;k<=n;++k){
		//printf("k=%d
",k);
		if (d[k].b+ps[k-1]>=sa){
			int pos=lower_bound(ps,ps+k,sa-d[k].b)-ps;
			if (pos<k){
				ll s=ps[pos];
				if (sa-s>=0)
				//printf("%d %lld (%lld,%lld)
",n-pos,s,(ll)(n-pos)*d[k].b-(sa-s),(ll)d[k].b);
				ans=max(ans,frac((ll)(n-pos)*d[k].b-(sa-s),d[k].b));
				//printf("(%lld,%lld)
",ans.u,ans.v);
			}
		}
		else{
			int pos=lower_bound(ps+k,ps+n+1,sa-d[k].b+max(d[k].a,d[k].b))-ps;
			if (pos<=n){
				ll s=ps[pos]-max(d[k].a,d[k].b);
				if (sa-s>=0)
				//printf("%d (%lld,%lld)
",n-(pos-1),sa-s,(ll)d[k].b);
				ans=max(ans,frac((ll)(n-(pos-1))*d[k].b-(sa-s),d[k].b));
				//printf("(%lld,%lld)
",ans.u,ans.v);
			}
		}
	}
	ans.v*=n;
	ans.adj();
	printf("%lld %lld
",ans.u,ans.v);
	return 0;
}
原文地址:https://www.cnblogs.com/jz-597/p/14732174.html