• hdu6070 Dirt Ratio 二分+线段树


    /**
    题目:hdu6070 Dirt Ratio
    链接:http://acm.hdu.edu.cn/showproblem.php?pid=6070
    题意:给定n个数,求1.0*x/y最小是多少。x表示一段区间内不同数字的个数,y表示区间长度。
    思路:二分+线段树
    二分答案x/y。 找一段区间满足 size(l,r)/(r-l+1) <= mid  , size(l,r)表示[l,r]内不同数的个数。
    
    size(l,r)<=mid(r-l+1) => size(l,r)+mid*l<=mid*(r+1);
    
    用线段树维护size(l,r)+mid*l的最小值。每一个节点存储size(l,r)+mid*l,枚举r,更新当前a[r]到不包含该数字的节点值+1
    
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    #define lson L,m,rt<<1
    #define rson m+1,R,rt<<1|1
    const double eps = 1e-4;
    const int N = 6e4+10;
    double add[N<<2], sum[N<<2];
    int last[N], a[N];
    void pushup(int rt)
    {
        sum[rt] = min(sum[rt<<1],sum[rt<<1|1]);
    }
    void pushdown(int rt)
    {
        sum[rt<<1] += add[rt];
        sum[rt<<1|1] += add[rt];
        add[rt<<1] += add[rt];
        add[rt<<1|1] += add[rt];
        add[rt] = 0;
    }
    void update(int l,int r,int L,int R,int rt,double d)
    {
        if(l<=L&&R<=r){
            sum[rt]+=d;
            add[rt]+=d;
            return ;
        }
        if(add[rt]>eps) pushdown(rt);
        int m = (L+R)/2;
        if(r<=m) update(l,r,lson,d);
        else if(l>m) update(l,r,rson,d);
        else{
            update(l,r,lson,d);
            update(l,r,rson,d);
        }
        pushup(rt);
    }
    double query(int l,int r,int L,int R,int rt)
    {
        if(l<=L&&R<=r){
            return sum[rt];
        }
        if(add[rt]>eps) pushdown(rt);
        int m = (L+R)/2;
        double mis;
        if(r<=m) mis = query(l,r,lson);
        else if(l>m) mis = query(l,r,rson);
        else mis = min(query(l,r,lson),query(l,r,rson));
        pushup(rt);
        return mis;
    }
    int main()
    {
        //freopen("C:\Users\accqx\Desktop\in.txt","r",stdin);
        int T, n;
        cin>>T;
        while(T--)
        {
            scanf("%d",&n);
            for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
            double hi = 1, lo = 0, mid;
            double temp;
            while(hi-lo>eps){
                mid = (hi+lo)/2;
                memset(add, 0, sizeof add);
                memset(sum, 0, sizeof sum);
                memset(last, 0, sizeof last);
                int flag = 0;
                for(int i = 1; i <= n; i++){
                    update(last[a[i]]+1,i,1,n,1,1);
                    update(i,i,1,n,1,mid*i);
                    temp = query(1,i,1,n,1);
                    if(temp<=mid*(i+1)){
                        flag = 1; break;
                    }
                    last[a[i]] = i;
                }
                if(flag) hi = mid;
                else lo = mid;
            }
            //cout<<mid<<endl;
            printf("%.10f
    ",mid);
        }
        return 0;
    }
  • 相关阅读:
    【04】Vue 之 事件处理
    【03】Vue 之列表渲染及条件渲染
    【02】 Vue 之 数据绑定
    传递参数的模式最适合向函数传入大量可先参数的情形
    ie6 PNG图片透明
    实现表单的输入框当光标为当前时,去掉默认值
    SSIS ->> Environment Variables
    SQL Server ->> FileTable
    SQL Server ->> 间接实现COUNT(DISTINCT XXX) OVER(PARTITION BY YYY)
    SQL Server ->> EXECUTE AS LOGIN/USER和Revert表达式
  • 原文地址:https://www.cnblogs.com/xiaochaoqun/p/7284859.html
Copyright © 2020-2023  润新知