题意
给定n个区间的左右端点l,r,找出最大区间不想交长度。n < 1e5 , l <= r < 1e6;
分析
感觉是用二分,一直纠结如何在二分中实现分数的产生。贪心的策略就是尽量分割出来的区间靠向左,为后面的留出更多的空间。
看了看 大神的,原来可以先二分出小数,再将小数转化为分数。。。
不过为毛 分母的范围是 1~n,还是不太懂啊 (懊恼.jpg)
代码
#include <bits/stdc++.h>
using namespace std;
int n;
const int maxn = 100000 + 100;
const int INF = 1000000 + 10;
const double eps = 1e-9;
struct pp
{
double l, r;
};
pp a[maxn];
bool cmp(pp a, pp b)
{
return a.l < b.l;
}
bool judge(double l)
{
int f = 1;
double s = 0;
for(int i = 0; i < n && f; i++)
{
if(s < a[i].l)
{
if(a[i].l + l <= a[i].r) {s = a[i].l+l; continue;}
else f = 0;
}
else
{
if(s + l <= a[i].r) {s += l; continue;}
else f = 0;
}
}
return f;
}
int main()
{
//freopen("in.txt","r", stdin);
while(cin >> n)
{
for(int i = 0; i< n; i++)
cin >> a[i].l >> a[i].r;
sort(a,a+n, cmp);
double ll = 0, rr = INF;
while(rr - ll > eps)
{
//int s1 = rr+ll, s2 *= 2;
double mid = (rr+ll)/2;
if(judge(mid)) ll = mid;
else rr = mid;
}
double ans = ll;
int rp = 0, rq = 1;
for(int p, q = 1; q <= n; ++q)
{
p = round(ans * q);
if(fabs((double)p/q - ans) < fabs((double)rp/rq - ans))
{
rp = p; rq = q;
}
}
printf("%d/%d\n", rp, rq);
}
return 0;
}