zoukankan      html  css  js  c++  java
  • hdu 6070 二分答案+线段树

    题意: 区间价值为    区间元素种类数  /  区间长度    问最小价值的区间是?

    思路:直接求解很困难,考虑二分答案判断,注意这题的关键是将二分答案后的不等式进行变换,如官方题解。二分答案 mid,检验是否存在一个区间满足 size(l,r)/(r−l+1) ≤ mid,也就是 size(l, r) + mid × l ≤mid × (r + 1)。

    之后的问题就很好解决了,枚举右端点,开一颗线段树来维护到当前节点的区间不同数(类似树状数组求区间不同数的想法来加入一个新点,主要是通过一个数组维护上一次出现的位置)+  mid × l ,这样就可以轻松判断是否存在解了。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define MEM(a,b) memset(a,b,sizeof(a))
    #define bug puts("bug");
    inline int ll(int k) {return 2*k;}
    inline int rr(int k) {return 2*k+1;}
    inline int mid(int kk1,int kk2) {return (kk1+kk2)>>1;}
    const int maxn=3e6+10;
    struct pr {
        double sum,lazy;
        int left,right;
    }tr[maxn+10];
    void pushdown(int k) {
        if(tr[k].lazy>1e-9){
            tr[ll(k)].sum+=tr[k].lazy;tr[rr(k)].sum+=tr[k].lazy;
            tr[ll(k)].lazy+=tr[k].lazy;
            tr[rr(k)].lazy+=tr[k].lazy;
            tr[k].lazy=0;
        }
    }
    void build(int k,int s,int t,double MI) {
        tr[k].left=s;tr[k].right=t;
        if(s==t) {tr[k].sum=t*MI;return;}
        build(ll(k),s,mid(s,t),MI);
        build(rr(k),mid(s,t)+1,t,MI);
        tr[k].sum=min(tr[ll(k)].sum,tr[rr(k)].sum);
        tr[k].lazy=0;
    }
    void modify(int k,int s,int t,int x) {
        int l=tr[k].left,r=tr[k].right;
        if(l==s&&r==t) {
            tr[k].lazy+=x,tr[k].sum+=x;
            return ;
        }
        pushdown(k);
        int mi=mid(l,r);
        if(t<=mi) modify(ll(k),s,t,x);
        else if(s>mi) modify(rr(k),s,t,x);
        else modify(ll(k),s,mi,x),modify(rr(k),mi+1,t,x);
        tr[k].sum=min(tr[ll(k)].sum,tr[rr(k)].sum);
    }
    double query(int k,int s,int t) {
        int l=tr[k].left,r=tr[k].right;
        if(l==s&&r==t) return tr[k].sum;
        pushdown(k);
        int mi=mid(l,r);
        double res=1e20;
        if (t<=mi) res=query(ll(k),s,t);
        else if(s>mi) res=query(rr(k),s,t);
        else res=min(query(ll(k),s,mi),query(rr(k),mi+1,t));
        return res;
    }
    int a[700000],last[700000],t,n;
    int cal(double x){
        build(1,1,n,x);
        MEM(last,0);
        for(int i=1;i<=n;i++){
            modify(1,last[a[i]]+1,i,1);
            last[a[i]]=i;
            if(query(1,1,i)<=x*(i+1)) return 1;
        }
        return 0;
    }
    
    int main(){
        scanf("%d",&t);
        while(t--){
            scanf("%d",&n);
            for(int i=1;i<=n;i++) scanf("%d",&a[i]);
            double L=0,R=1.0,mi;
            for(int i=0;i<25;i++){
                mi=(L+R)/2;
                if(cal(mi)) R=mi;
                else L=mi;
            }
            printf("%.8f
    ",R);
        }
        return 0;
    }



  • 相关阅读:
    codeforces 732D
    我的ubuntu配置
    周末实在无聊,自己写了一遍被人写烂了的“贪吃蛇”,欢迎各位新手低手高手老手前来吐槽哈哈
    两种方式实现点击列表弹出列表索引
    浅谈javascript中原型(prototype)、构造函数、对象实例及三者之间的关系
    写了个超级简单的“进度条”的demo,供新手参考,高手吐槽!
    javascript 使用 NodeList主意的问题
    js中的“||”和“&&”
    javascript call函数实现继承时遇到的问题
    javascript 解决innerText浏览器兼容
  • 原文地址:https://www.cnblogs.com/zhangxianlong/p/10672507.html
Copyright © 2011-2022 走看看