• [HDU6240]Server


    题目大意:
      用$n$条线段覆盖区间$[1,t]$上的整点。每条线段有4个属性$(S_i,T_i,A_i,B_i)$,表示用第$i$条线段可以覆盖区间$[S_i,T_i]$。若选取线段的集合为$S$,最后总代价为$frac{sum_{iin S}A_i}{sum_{iin S}B_i}$。问区间$[1,t]$全部覆盖时,最小代价为多少?

    思路:
      分数规划经典模型。
      二分答案$k$,表示代价为$k$。若$k$为可行的,则我代价们需要找到一个合法的$S$,满足$frac{sum_{iin S}A_i}{sum_{iin S}B_i}leq k$。移项得$sum_{iin S}(A_ik-B_i)geq 0$。
      可以将所有线段按照左端点排序,然后考虑每个线段对答案的贡献。
      若$A_ik-B_igeq 0$,则选了这个线段肯定能够让答案尽可能大于$0$,因此把它选上。
      如果把所有$A_ik-B_igeq 0$的线段选上后能够覆盖完整个区间,那么$k$为可行的代价。
      如果不能覆盖完,那么我们要考虑选上一些$A_ik-B_i<0$的线段,使得代价增加最少的情况下,能把区间覆盖完。
      若用$sum$表示必选线段$A_ik-B_i$的和,$f_i$表示覆盖完$i$点后,$sum$要减少的值。那么对于必选线段$i$,$f_{r_i}=min{f_jmid S_ileq jleq t}$(选了以后并不会影响$sum$),对于其它线段,$f_{r_i}=min{f_j|S_ileq jleq t}+B_i-A_ik$。由于$f_{r_i}$,可能会被计算多次,因此取最小值即可。转移的时候相当于后缀最小值,显然可以使用树状数组优化。最后只需要判断$sum-f_tgeq 0$即可。

     1 #include<cstdio>
     2 #include<cctype>
     3 #include<algorithm>
     4 inline int getint() {
     5     register char ch;
     6     while(!isdigit(ch=getchar()));
     7     register int x=ch^'0';
     8     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
     9     return x;
    10 }
    11 const int N=100001;
    12 const double eps=1e-5,inf=1e10;
    13 struct Node {
    14     int l,r,w,a;
    15     bool operator < (const Node &another) const {
    16         return l<another.l||(l==another.l&&r<another.r);
    17     }
    18 };
    19 Node node[N];
    20 int n,m;
    21 struct SuffixFenwickTree {
    22     double val[N];
    23     int lowbit(const int &x) const {
    24         return x&-x;
    25     }
    26     void reset() {
    27         for(register int i=1;i<=m;i++) {
    28             val[i]=-inf;
    29         }
    30     }
    31     void modify(int p,const double &x) {
    32         while(p) {
    33             val[p]=std::max(val[p],x);
    34             p-=lowbit(p);
    35         }
    36     }
    37     double query(int p) const {
    38         if(!p) return 0;
    39         double ret=-inf;
    40         while(p<=m) {
    41             ret=std::max(ret,val[p]);
    42             p+=lowbit(p);
    43         }
    44         return ret;
    45     }
    46 };
    47 SuffixFenwickTree t;
    48 inline bool check(const double &k) {
    49     t.reset();
    50     int last=0;
    51     for(register int i=1;i<=n;i++) {
    52         if(node[i].a*k-node[i].w<0) continue;
    53         if(node[i].l-1<=last) last=std::max(last,node[i].r);
    54     }
    55     if(last>=m) return true;
    56     double sum=0;
    57     t.modify(last,0);
    58     for(register int i=1;i<=n;i++) {
    59         if(node[i].a*k-node[i].w<0) {
    60             t.modify(node[i].r,t.query(node[i].l-1)+node[i].a*k-node[i].w);
    61         } else {
    62             sum+=node[i].a*k-node[i].w;
    63             t.modify(node[i].r,t.query(node[i].l-1));
    64         }
    65     }
    66     return sum+t.query(m)>=0;
    67 }
    68 int main() {
    69     for(register int T=getint();T;T--) {
    70         n=getint(),m=getint();
    71         int sumw=0,suma=0;
    72         for(register int i=1;i<=n;i++) {
    73             const int l=getint(),r=getint(),w=getint(),a=getint();
    74             sumw+=w,suma+=a;
    75             node[i]=(Node){l,r,w,a};
    76         }
    77         std::sort(&node[1],&node[n+1]);
    78         double l=0,r=sumw*1./suma;
    79         while(r-l>=eps) {
    80             const double mid=(l+r)/2;
    81             (check(mid)?r:l)=mid;
    82         }
    83         printf("%.3f
    ",r);
    84     }
    85     return 0;
    86 }
  • 相关阅读:
    ZOJ 3713 In 7-bit (题意不好理解,十进制、二进制、十六进制的转换问题)
    C++ cout 如何保留小数输出
    ZOJ 3705 Applications 模拟
    Google Code Jam Round 1A 2015 Problem B. Haircut 二分
    --算法分析与设计--课程作业--【顺序统计】--【采用链表法散列表】--【开放地址法(双重散列)】
    C++获取当前时间和计算程序运行时间的方法
    【STL__set_的应用】
    ZOJ 3601 Unrequited Love 【STL__pair_的应用】
    Linux概念
    fragment创建
  • 原文地址:https://www.cnblogs.com/skylee03/p/8275829.html
Copyright © 2020-2023  润新知