HDU 6240 Server(2017CCPC哈爾濱 K)01分數規劃+樹狀數組優化dp

題目傳送門

Server

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


 

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
 

 

Source
 

 

Recommend
jiangzijing2015   |   We have carefully selected several similar problems for you:  6742 6741 6740 6739 6738 
 
 
題意:給定n(<=1e5)個物品和t(<=1e5),每種物品有四個屬性l,r,a,b(a,b<=1000)。
其中l,r表示這個物品可以覆蓋區間[l,r]。r最大爲t。
現在讓你選出若干個物品覆蓋[1,t],保證答案存在,求最小的

\frac{\sum_{i\epsilon S}a_{i}}{\sum_{i\epsilon S}b_{i}},其中S爲被選中物品的下標的集合。

思路:

很容易想到是01分數規劃,二分答案mid,然後每個物品的價值就是bi*mid-ai。

對於價值大於0的物品,我們直接選擇它並記錄價值和sum、能覆蓋到的最右端點mx。

這時問題轉化成了,從剩下的物品中,用盡可能小的花費覆蓋[1,t]。由於題目保證答案存在,因此我們只考慮覆蓋t點最小花費。

按區間左端點爲第一關鍵字,右端點爲第二關鍵字排序。這樣就可以使用線段樹/樹狀數組優化dp來做。

具體做法:

處理完sum和mx後,將其他點的價值處理爲inf,mx點的價值處理爲0。

依次遍歷i=1~n,如果價值大於零,直接用[ a[i].l-1 , t ]中的最小花費更新a[i].r點的最小花費,否則用[ a[i].l-1 , t ]中的最小花費-(bi*mid-ai)更新a[i].r點的最小花費,最後判斷sum是否大於覆蓋t點的花費即可。

總體複雜度爲O(nlogn)或O(nlogt),還有一個二分的常數。

代碼:
#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define mst(head,x,n) memset(head+1,x,n*sizeof(head[0]))
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int maxn=2e5+5;
//const double pi=acos(-1.0);
const double eps=1e-5;
//const ll mo=1e9+7;
int n,m,k;
double ans,tmp,cnt;
int flag;
double c[maxn];
template <typename T>
inline void read(T &X){
    X=0;int w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    if(w) X=-X;
}
struct node{
    int l,r;
    double xa,xb;
    int fg;
    bool operator<(node aa)const{
        return l<aa.l||(l==aa.l&&r<aa.r);
    }
}a[maxn];
int lb(int x){return x&(-x);}
void add(int x,double v){
    while(x>0){
        c[x]=min(c[x],v);
        x-=lb(x);
    }
}
double query(int x){
    if(x==0) return 0;
    double ans=inf;
    while(x<=k){
        ans=min(ans,c[x]);
        x+=lb(x);
    }
    return ans;
}
int jud(double md){
    double sum=0;
    int mx=0;
    rep(i,1,k) c[i]=inf;
    rep(i,1,n){
        if(a[i].xb*md>a[i].xa){
            sum+=a[i].xb*md-a[i].xa;
            if(a[i].l-1<=mx) mx=max(mx,a[i].r);
            a[i].fg=1;
        }
        else a[i].fg=0;
    }
    add(mx,0);
    rep(i,1,n) {
        if(a[i].fg){
            double s=query(a[i].l-1);
            add(a[i].r,s);
        }
        else {
            double s=query(a[i].l-1);
            add(a[i].r,s-a[i].xb*md+a[i].xa);
        }
    }
    return sum>=query(k);
}
int main(){
    int T,cas=1;
    read(T);
    while(T--)
    {
        read(n);read(k);
        rep(i,1,n){
            scanf("%d%d%lf%lf",&a[i].l,&a[i].r,&a[i].xa,&a[i].xb);
        }
        sort(a+1,a+1+n);
        double l=0,r=1001;
        while(r-l>eps){
            double mid=(l+r)/2.0;
            if(jud(mid)) r=mid;
            else l=mid;
        }
        printf("%.3f\n",l);
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章