Server
Problem Description
Alice and Bob are working on a new assignment. In this project, they need to access some information on a website and monitor this web site for consistent t days. In others words, in each day, there must be at least one server in work. Luckily, they can rent some servers in the lab. According to the schedule, there are totally N servers being available. The i-th server can be used from the Si-th day to the Ti-th day. However, using the i-th server require A i A_i Ai dollars. After a long time of persuasion, the administrator of the machine room agree to give Alice and Bob discount. Each server is assigned with a discount number Bi. If the set of servers they want to use is S, they need to pay ∑ i ∈ S A i ∑ i ∈ S B i \frac{∑_{i∈S} A_i}{∑_{i∈S}B_i} ∑i∈SBi∑i∈SAi dollars. As Alice and Bob are preparing the programs on the servers, they want your help to find a way to minimize the cost of servers.
Input
The first line is the number of test cases. For each test case, the first contains two positive integers N and t ( N ≤ 100000 N≤100000 N≤100000, t ≤ 100000 t≤100000 t≤100000) as described above. In the next N lines, the i-th line consists of four integer S i S_i Si, T i T_i Ti, A i A_i Ai, and B i B_i Bi ( 1 ≤ S i ≤ T i ≤ t 1≤S_i≤T_i≤t 1≤Si≤Ti≤t, 0 < A i , B i ≤ 1000 0<A_i,B_i≤1000 0<Ai,Bi≤1000).
Output
For each test case, output an float-point number with three decimal places donating the minimum cost Alice and Bob need to pay. It is guaranteed that there is at least one feasible way to rent servers.
Sample Input
1
4 5
1 3 28 1
4 5 22 1
3 5 34 1
1 2 26 1
Sample Output
25.000
题意
有n个物品,每个物品有四个值si,ti,Ai和Bi,代表si~ti时刻可用。需要选择部分物品,使时间1~t内都有物品可用,同时使所有物品的(Ai和)/(Bi和)最小。
题解:
∑
i
∈
S
A
i
∑
i
∈
S
B
i
\frac{∑_{i∈S} A_i}{∑_{i∈S}B_i}
∑i∈SBi∑i∈SAi最小,显然是分数规划问题,利用二分求解。
在求出
d
i
=
a
i
−
m
i
d
∗
b
i
di = ai-mid*bi
di=ai−mid∗bi后,求出满足条件的最大和。
显然若di>0,则必选,将sum+=di,且另该物品di为0。
将所有的物品排序,以ti为关键字,
需满足所有点都被覆盖。若一个物品可以覆盖[l,r],
则
d
p
[
r
]
=
m
a
x
(
d
p
[
r
]
,
d
p
[
i
]
)
dp[r] = max(dp[r], dp[i])
dp[r]=max(dp[r],dp[i]),
i
∈
[
l
−
1
,
r
]
i\in[l-1,r]
i∈[l−1,r]。
求区间最大值,可以利用树状数组来维护(线段树慎用,可能会T)。
因为该问题的特殊性,若不将di>0的提前取出,可能会导致dp出错。
最后是否判断
s
u
m
+
d
p
[
r
]
≥
0
sum+dp[r]\ge0
sum+dp[r]≥0即可。
因为上面二分实际上求的是
∑
i
∈
S
B
i
∑
i
∈
S
A
i
\frac{∑_{i∈S}B_i}{∑_{i∈S} A_i}
∑i∈SAi∑i∈SBi的最大值,所以最后还要求倒数。
#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<set>
#include<vector>
#include<queue>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-6
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 100100;
const int mod = 3000001;
struct node{
int s, t, a, b;
double d;
}p[maxn];
double a[maxn], h[maxn];
int lowbit(int x);
bool isok(int n, int t);
bool cmp(node a, node b);
double query(int l, int r);
void Update(int x, double y, int n);
int main()
{
int n, t, i, j, k, cas;
scanf("%d", &cas);
while(cas--)
{
scanf("%d%d", &n, &t);
for(i=0;i<n;i++)
scanf("%d %d %d %d", &p[i].s, &p[i].t, &p[i].a, &p[i].b);
sort(p, p+n, cmp);
double l = 0.00001, r = 1e3;
while(l+eps<r)
{
double mid = (l+r)/2;
for(i=0;i<n;i++)
p[i].d = p[i].b-mid*p[i].a;
if(isok(n, t))l = mid;
else r = mid;
}
printf("%.3f\n", 1.0/l);
}
return 0;
}
bool isok(int n, int t)
{
double x, sum = 0.0;
for(int i=1;i<=t;i++)a[i] = h[i] = -1e10;
for(int i=0;i<n;i++){
if(p[i].d >0)sum += p[i].d, p[i].d = 0.0;
if(p[i].s == 1)x = max(0.0, query(p[i].s, p[i].t));
else x = query(p[i].s-1, p[i].t);
Update(p[i].t, x+p[i].d, t);
a[p[i].t] = max(a[p[i].t], x+p[i].d);
}
return a[t]+sum>=0.0;
}
int lowbit(int x)
{
return x&(-x);
}
void Update(int x, double y, int n)
{
for(int i=x;i<=n;i+=lowbit(i))
h[i] = max(h[i], y);
}
double query(int l, int r)
{
double mx = -1e10;
while(r>=l){
if(r-lowbit(r)>=l-1){
mx = max(mx, h[r]);
r -= lowbit(r);
}else{
mx = max(mx, a[r]);
r--;
}
}
return mx;
}
bool cmp(node a, node b)
{
return a.t < b.t;
}