HDU_6240 Server(分数规划+树状数组)

Server

Time Limit: 20000/10000 MS (Java/Others)
Memory Limit: 262144/262144 K (Java/Others)
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} iSBiiSAi 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 N100000, t ≤ 100000 t≤100000 t100000) 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 1SiTit, 0 < A i , B i ≤ 1000 0<A_i,B_i≤1000 0<Ai,Bi1000).

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} iSBiiSAi最小,显然是分数规划问题,利用二分求解。
在求出 d i = a i − m i d ∗ b i di = ai-mid*bi di=aimidbi后,求出满足条件的最大和。
显然若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[l1,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} iSAiiSBi的最大值,所以最后还要求倒数。

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值