• HDU-6070 Dirt Ratio(二分+线段树+分数规划)


    (有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

    目录

    题意:传送门

     原题目描述在最下面。
     求(sum/len)最小值。(sum)是一段区间内不同数字的个数,(len)是这段区间的长度。

    思路:

     首先预处理出每个数上一次出现的位置(pre[i])和最后一次出现的位置(lst[i])。这个操作在静态求区间内不同数的个数动态求区间内不同数的个数都有用到。

    法一:
     二分答案(mid)。枚举序列,每加入一个数就在(pre[i]-i)区间加一,因为在以(i)为右端点的所有区间内,这么区间多了一个新数字。

     对于(sum/lenleq mid; ightarrow sum - len * mid leq 0)。我们已经处理了(sum),对于(len*mid),就在解决每次插入一个数后,在(1-i)区间减去(k)。最后查询区间最小值,如果小于(0)则此(mid)符合还可以更小。

     因为我们每加入一个数后,查询的是以(i)为右端点的区间最小值,所以很自然的就要(1-i)每次减去(k)。这样才符合上述表达式。感觉画个图更好理解。


    法二:
     化简表达式为:$sum(L,R)+Lmid leq Rmid $

    (sum)的更新和上面一样,但是左边多了一项(l*mid)

     怎么办呢?解决方法就是在线段树的每个端点处的值初始化为(l*mid)((l)是到(1)的距离)。

     然后每此更新完后查询区间最小值(mmin),如果(mminleq i*mid)则此(mid)符合还可以更小

    AC代码:

    #include<bits/stdc++.h> 
    #define lson rt<<1
    #define rson rt<<1|1
    #define mme(a,b) memset((a),(b),sizeof((a)))  
    using namespace std;
    const int N = 1e5+7;
    int n;
    int lst[N],pre[N],ar[N];
    double sum[N<<2],lazy[N<<2];
    void push_up(int rt){
      sum[rt]=min(sum[lson],sum[rson]);
    }
    void push_down(int rt){
      if(lazy[rt]){
        lazy[lson]+=lazy[rt];
        lazy[rson]+=lazy[rt];
        sum[lson]+=lazy[rt];
        sum[rson]+=lazy[rt];
        lazy[rt]=0;
      }
    }
    void update(int L,int R,int l,int r,double c,int rt){
      if(L<=l&&r<=R){
        sum[rt] += c;
        lazy[rt] += c;
        return;
      }
      push_down(rt);
      int mid = (l+r)>>1;
      if(L<=mid) update(L,R,l,mid,c,lson);
      if(R>mid) update(L,R,mid+1,r,c,rson);
      push_up(rt);
    }
    double query(int L,int R,int l,int r,int rt){
      if(L<=l&&r<=R){
        return sum[rt];
      }
      push_down(rt);
      int mid = (l+r)>>1;
      double sum=n;
      if(L<=mid) sum = min(sum, query(L,R,l,mid,lson));
      if(R>mid) sum = min(sum, query(L,R,mid+1,r,rson));
      push_up(rt);
      return sum;
    }
    /*
    1
    5
    1 2 1 2 3
    sum/len最小值
    sum/len <= mid
    sum - len*mid <= 0
    sum 区间不同数字的个数
    len 区间长度
    */
    bool ok(double e){
      mme(sum,0);mme(lazy,0);
      for(int i=1;i<=n;++i){
        update(pre[i]+1,i,1,n,1,1);
        update(1,i,1,n,-e,1);
        if(query(1,i,1,n,1)<=0)return 1;
      }
      return false;
    }
    int main(){
      int tim;
      scanf("%d",&tim);
      while(tim--){
        scanf("%d",&n);
        mme(lst,0);mme(pre,0);
        for(int i=1;i<=n;++i){
          scanf("%d",&ar[i]);
          pre[i]=lst[ar[i]];
          lst[ar[i]]=i;
        }
        double l=0,r=1,mid;
        for(int i=0;i<20;++i){
          mid=(l+r)/2;
          if(ok(mid))r=mid;
          else l=mid;
        }
        printf("%.5f
    ", r);
      }
      return 0;
    }
    

    ####原题目描述: ![这里写图片描述](https://img-blog.csdn.net/20180808090410937?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5NTk5MDY3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
  • 相关阅读:
    【转载】中文分词整理
    【转载】浅谈事件冒泡与事件捕获
    【转载】SpringCloud-Eurek 心跳阈值说明
    【转载】Linux下查看CPU、内存占用率
    Linux内存、性能诊断中vmstat命令的详解
    【转载】springboot四 全局异常处理
    【转载】linux系统时间自动同步:ntp
    springboot整合三 共享session,集成springsession
    git把一个分支上的某个提交合并到另一个分支
    VS Code打开新的文件会覆盖窗口中的,怎么改
  • 原文地址:https://www.cnblogs.com/Cwolf9/p/9440289.html
Copyright © 2020-2023  润新知