zoukankan      html  css  js  c++  java
  • 2017 多校4 Dirt Ratio

    多校4 Dirt Ratio(二分+线段树)

    题意:

    给出n个数,找一段区间使得区间内不同数字个数除以区间长度最小,求这个最小值,(n<=60000,a_i<=n)

    题解:

    二分答案mid,检验是否存在一个区间满足(frac{size(l,r)}{r-l+1}leq mid ​),也就是(size(l,r)+mid imes lleq mid imes (r+1))

    从左往右枚举每个位置作(r),当rr变化为(r+1)时,对(size)的影响是一段区间加1,线段树维护区间最小值即可。

    时间复杂度(O(nlog nlog w))

    二分答案和枚举端点想到了,但是求最小值只会遍历,复杂度太高,没想到还能线段树维护,get新技能了。
    从左往右枚举右端点,那么第(i)个数的贡献就是(last[a[i]]+1到i),第i个数都是有贡献的,然后就用线段树搞搞,这样就降了一维复杂度了。

    #include<bits/stdc++.h>
    #define LL long long
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define ls (rt<<1)
    #define rs (rt<<1|1)
    using namespace std;
    const int N = 6e4 + 10;
    const double eps = 1e-6;
    int read(){
        int x = 0;
        char c = getchar();
        while(c < '0' || c >'9') c = getchar();
        while(c >= '0' && c <= '9') x = x * 10 + c - 48 , c = getchar();
        return x;
    }
    int n;
    int c[N],last[N],pre[N];
    double s[N<<2],col[N<<2];
    void pushup(int rt){
        s[rt] = min(s[ls],s[rs]);
    }
    void pushdown(int rt,int m){
        if(col[rt] > eps){
            col[ls] += col[rt];
            col[rs] += col[rt];
            s[ls] += col[rt];
            s[rs] += col[rt];
            col[rt] = 0;
        }
    }
    void update(int L,int R,double val,int l,int r,int rt){
        if(L <= l && R >= r){
            s[rt] += val;
            col[rt] += val;
            return ;
        }
        pushdown(rt,r - l + 1);
        int m = l + r >> 1;
        if(L <= m) update(L,R,val,lson);
        if(R > m) update(L,R,val,rson);
        pushup(rt);
    }
    double query(int L,int R,int l,int r,int rt){
        if(L <= l && R >= r){
            return s[rt];
        }
        pushdown(rt,r - l + 1);
        int m = l + r >> 1;
        double ans = 100000000;
        if(L <= m) ans = min(ans,query(L,R,lson));
        if(R > m) ans = min(ans,query(L,R,rson));
        return ans;
    }
    bool check(double mid){
        memset(s,0,sizeof(s));
        memset(col,0,sizeof(col));
        for(int i = 1;i <= n;i++){
            update(last[i]+1,i,1,1,n,1);
            update(i,i,mid * i,1,n,1);
            double res = query(1,i,1,n,1);
           // printf("%d %.6f
    ",i,res);
            if(mid * (i + 1) - res > eps) return true;
        }
        return false;
    }
    int main(){
    
        int T;
        T = read();
        while(T--){
          n = read();
          memset(pre,0,sizeof(pre));
          for(int i = 1;i <= n;i++) {
            c[i] = read();
            last[i] = pre[c[i]];
            pre[c[i]] = i;
          }
          double l = 0,r = 1,ans = r;
          while(r - l > eps){
            double mid = (l + r) / 2;
            if(check(mid)) ans = min(ans,mid),r = mid;
            else l = mid;
          }
          printf("%.6lf
    ",ans);
        }
        return 0;
    }
    
    
    
  • 相关阅读:
    C#:foreach语句,yield语句
    C#:委托
    C#:事件
    fckeditor 添加上传附件功能
    电话号码 正则表达式
    设为首页,和加入收藏js代码
    sql中判断时间,精确到秒
    js 日期 星期
    那些惊艳的句子!
    .net 动态页面生成静态页面
  • 原文地址:https://www.cnblogs.com/jiachinzhao/p/7284439.html
Copyright © 2011-2022 走看看