Portal
首先考虑一个固定的顺序如何计算概率,就是设
d
d
d为
m
a
x
i
=
1
n
∑
j
=
1
i
b
(
j
)
−
a
(
j
)
max_{i=1}^n\sum_{j=1}^ib(j)-a(j)
maxi=1n∑j=1ib(j)−a(j),然后
R
i
n
g
o
Ringo
Ringo从起点走
d
d
d秒的距离占总长的比例就是答案了。证明显然。
整数部分指那些被完全经过的平衡木,小数部分指那个被部分经过的平衡木(可能不存在)。
然后先考虑如何计算答案的整数部分。由上述式子可理解为一个平衡木的贡献为
b
(
i
)
−
a
(
i
)
b(i)-a(i)
b(i)−a(i),若它要被作为整数部分,也就是被完全经过,就会产生代价
b
(
i
)
b(i)
b(i),综合起来它的贡献就变了
−
a
(
i
)
-a(i)
−a(i)。因为一个平衡木被完全经过的话一定是产生负贡献,所以若想合法(即总和不为负),肯定是需要其它平衡木的正贡献。那么一开始可以把所有
b
(
i
)
−
a
(
i
)
>
=
0
b(i)-a(i)>=0
b(i)−a(i)>=0的平衡木的贡献
b
(
i
)
−
a
(
i
)
b(i)-a(i)
b(i)−a(i)加起来,结果为
s
u
m
sum
sum,但可能其中的点
i
i
i是被要被完全经过的,可易发现减掉
b
(
i
)
b(i)
b(i)就可以达成这个情况了,那么
b
(
i
)
−
a
(
i
)
>
=
0
b(i)-a(i)>=0
b(i)−a(i)>=0的平衡木贡献就不是
−
a
(
i
)
-a(i)
−a(i)了,是
−
b
(
i
)
-b(i)
−b(i)。
所以整数部分的计算就很容易了,就是要你选尽量多的点,使得它们的贡献(即
−
m
a
x
(
a
(
i
)
,
b
(
i
)
)
-max(a(i),b(i))
−max(a(i),b(i)))和加
s
u
m
sum
sum不小于
0
0
0,而这个按贡献绝对值从小到大排序后贪心做就行了。但小数部分怎么办呢?其实也很容易,就是先枚举是在哪个平衡木上,然后肯定是要最大化整数部分,类似上述做就行了,不过由于不能用枚举到的平衡木,所以只能二分来求,然后
s
u
m
sum
sum加上整数部分的贡献后剩余的秒数就是在这个平衡木上走的秒数了(并没有这么简单,还有一些特殊的地方,具体看代码)。最后答案就只要所有的情况下的答案取个
m
a
x
max
max就行了。
时间复杂度是
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)的,可以通过本题。
官方题解做法(好像本质上没有区别。。。)
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
int stack[20];
inline void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x),putchar(' ');}
inline void pr2(int x){write(x),puts("");}
struct node
{
int x,y;
}a[100010];
bool cmp(node a,node b){return max(a.x,a.y)<max(b.x,b.y);}
int n;
long long sum,s[100010];
inline int erfen(int pos)
{
int l=1,r=n,p=0,d=max(a[pos].x,a[pos].y);
while(l<=r)
{
int mid=l+r>>1;
long long uf=s[mid];if(mid>=pos)uf-=d;
if(uf<=sum)p=mid,l=mid+1;
else r=mid-1;
}return p;
}
inline long long gcd(long long x,long long y)
{
if(x==0)return y;
else return gcd(y%x,x);
}
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
n=read();
for(int i=1;i<=n;i++)a[i].x=read(),a[i].y=read();
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
s[i]=s[i-1]+max(a[i].x,a[i].y);
if(a[i].y>a[i].x)sum+=a[i].y-a[i].x;
}
long long ax=0,ay=1,x,y,ul;
for(int i=1;i<=n;i++)
{
x=erfen(i);long long uf=sum-s[x];if(x>=i)x--,uf+=max(a[i].x,a[i].y);
if(a[i].y>a[i].x)uf-=a[i].y-a[i].x;
x=x*a[i].y+min(uf+a[i].y-a[i].x,1LL*a[i].y),y=1LL*n*a[i].y;ul=gcd(x,y);
if(x<=0)continue;
x/=ul,y/=ul;
long long he=gcd(ay,y);
if(1.0*ay/he*x>1.0*y/he*ax)ax=x,ay=y;//爆ll
}
printf("%lld %lld\n",ax,ay);
return 0;
}