大体题意:
给你n 个线段,要求重新规划每个线段,使得每个线段的长度都一样,并且线段之间没有交点,问线段的最大长度是多少?
思路:
很容易想到二分线段的最大长度,然后看这个长度是否合适,合适就往右划分,不合适就往左划分。
我直接说正解了:
因为是输出分数,我们应该二分的时候用小数,然后小数变分数,找一个最接近的分数即可,枚举分母计算分子就可以。
吐槽:
一开始用的分数类二分,这样肯定不行的,因为精度一高的话,分子分母会很大,很容易爆int 和longlong,不爆的话 还无法得到正确的答案。
因此肯定是二分小数咯。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;
const int maxn = 1e5+7;
const double eps = 1e-10;
typedef long long LL;
int dcmp(double a,double b){
if (fabs(a-b) < eps) return 0;
if (a > b) return 1;
return -1;
}
int n;
struct Node{
int l,r;
void read(){
scanf("%d %d",&l, &r);
}
bool operator < (const Node& rhs) const {
return r < rhs.r || (r == rhs.r && l < rhs.l);
}
}p[maxn];
int gcd(int a,int b){
return !b? a : gcd(b,a%b);
}
double mid;
bool solve(){
double la = -1.0;
for (int i = 0; i < n; ++i){
if ( dcmp(p[i].l,la) >= 0){
la = p[i].l + mid;
}
else {
if ( (la+mid) > p[i].r ) return false;
la += mid;
}
}
return true;
}
int main(){
while(~scanf("%d",&n)){
int Rr=0x3f3f3f3f;
for (int i = 0; i < n; ++i) {
p[i].read();
if (p[i].r - p[i].l < Rr) Rr = p[i].r - p[i].l;
}
sort(p,p+n);
double L = 0,R = Rr*1.0;
while(R-L > eps){
mid = (L+R)/2.0;
if (solve()) L = mid;
else R = mid;
}
L = (L+R)/2.0;
double ans = 1e18;
int fz;
int fm;
for (int i = 1; i <= 100000; ++i){
int j = floor(i*L);
if (dcmp( fabs((j*1.0)/i-L) , ans) == -1) {
ans = fabs((j*1.0)/i - L);
fz = j;
fm = i;
}
j = ceil(i*L);
if (dcmp( fabs((j*1.0)/i-L) , ans) == -1) {
ans = fabs((j*1.0)/i - L);
fz = j;
fm = i;
}
}
int g = gcd(fz,fm);
fz /= g;
fm /= g;
printf("%d/%d\n",fz,fm);
}
return 0;
}
/**
3
2 6
1 4
8 12
**/