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;
}
原文地址:https://www.cnblogs.com/xiaochaoqun/p/7284859.html