hdu 6240

Server

Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 623 Accepted Submission(s): 94

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 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∈SAi∑i∈SBi 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,t≤100000) as described above. In the next N lines, the i-th line consists of four integer Si, Ti, Ai, and Bi (1≤Si≤Ti≤t, 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个服务器,每个服务器的工作时间是s到t,花费是a,b;选出一些服务器的集合s,求选出一个集合使得集合中的服务器(所有a的和)/(所有b的和) 最小。
做法:01分数规划,之前做过一个分数规划,现在感觉当时不是很理解。我现在对分数规划的理解是:对于给出的数据,选中和不选中有正的影响(是答案变大)或者有负的影响(使答案变小),而一般情况下我们做的dp题他们的影响都是一样的,会使结果变差,然后可以用dp找出所有结果中最好的那个,而对于这种题dp就不行了,因为有些边产生的影响不一样,所以不能直接dp,然后就可以通过二分解决了,二分答案,这样就可以把边分成两类,1:产生正影响,2:产生负影响。1的边选中,然后用dp从第二种边中找出产生负影响最小的方案,然后比较产生正影响和负影响的和。正影响和负影响的计算方法是加上mid*pt[i].b - pt[i].a;所有正影响大于负影响,那么说明可行,否则就说明不行。
优化:最开始我用线段树维护区间最小值,但是跑了9s多,差点超时,然后学习到了一个新的快一点维护区间最小值的方法,用数状数组去维护,跑了3s不到。

#include<bits/stdc++.h>
using namespace std;
const int N  = 1e5+100;

int T,n,t;
double sum[N<<2];
struct node{
    int l,r,a,b;
    bool operator<(const node &p)const{
        return l < p.l;
    }
    bool judge(double x){
        return a*1.0/b < x;
    }
}pt[N];
/*
void build(int l,int r,int rt){
    if(l == r) {
        sum[rt] = 1e9;
        return ;
    }
    int mid = l+r>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    sum[rt] = min(sum[rt<<1],sum[rt<<1|1]);
}
void update(int x,double c,int l,int r,int rt){
    if(l == r){
        sum[rt] = min(sum[rt],c);
        return ;
    }
    int mid = l+r>>1;
    if(mid >= x) update(x,c,l,mid,rt<<1);
    else update(x,c,mid+1,r,rt<<1|1);
    sum[rt] = min(sum[rt<<1],sum[rt<<1|1]);
}

double query(int L,int R,int l,int r,int rt){
    if(L <= 0) return 0;
    if(L <= l && R >= r){
        return sum[rt];
    }
    int mid = l+r>>1;
    double ret = 1e9;
    if(mid >= L) ret = query(L,R,l,mid,rt<<1);
    if(mid < R) ret = min(ret,query(L,R,mid+1,r,rt<<1|1));
    return ret;
}
*/
int lowbit(int x){
    return x&(-x);
}
void update(int x,double c){
    while(x > 0){
        sum[x] = min(sum[x],c);
        x -= lowbit(x);
    }
}
double query(int x){
    if(x == 0) return 0;
    double ret = 1e9;
    while(x <= t){
        ret = min(ret,sum[x]);
        x += lowbit(x);
    }
    return ret;
}

bool check(double x){
    double ret = 0;
    for(int i = 1;i <= t;i ++){
        sum[i]= 1e9;
    }
    for(int i = 1;i <= n;i ++){
        if(pt[i].judge(x)) ret += x*pt[i].b - pt[i].a;
    }
    for(int i = 1;i <= n;i ++){
        double now = query(pt[i].l-1);
        //cout << x << ' '<< i << ' '<<now << ' ' << pt[i].l << ' ' <<pt[i].r << endl;
        if(!pt[i].judge(x)) now +=  pt[i].a - x*pt[i].b;
        update(pt[i].r,now);
    }
    //cout << x << ' '<< sum << ' ' << query(t,t,1,t,1)<<endl;
    return ret >= query(t);
}

int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d %d",&n,&t);
        for(int i = 1;i <= n;i ++){
            scanf("%d %d %d %d",&pt[i].l,&pt[i].r,&pt[i].a,&pt[i].b);
        }
        sort(pt+1,pt+n+1);
        double l = 0,r = 1001;
        for(int i = 1;i <= 25;i ++){
            double mid= (l+r)/2.0;
            //cout << "!!!" << l << ' '<< r << ' '<< mid << endl;
            if(check(mid)) r = mid;
            else l = mid;
        }
        printf("%.3f\n",r);
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值