hdu6070 Dirt Ratio(二分+线段树)

来源:互联网 发布:java书籍顺序推荐 知乎 编辑:程序博客网 时间:2024/06/06 01:36

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6070

题意:在区间[l,r]中,不同数的个数/区间长度的最小值

解:

用二分找答案最小值,用size(l,r)/(r-l+1)<=mid来判断答案是否最小。

公式可以转化为size(l,r)+l*mid<=(r+1)*mid,可以用线段树来维护l*mid的最小值。

利用线段树更新的是数字出现的次数,使用pre数组来记录时,更新新一段的区间里的次数,因为上一个相同的数字已经没有了贡献。

代码:

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#define mem(a,b) memset(a,0,sizeof(a))using namespace std;const int maxn=6e4+50;const double esp=1e-5;int a[maxn];int pre[maxn],pos[maxn];struct Tree{    int l,r,node;    double v,lazy;}seg[maxn<<2];/*void init(){        for(int i=1;i<=maxn;i++)        {            seg[i].v=0.0;            seg[i].lazy=0.0;        }}*/void pushup(int node){seg[node].v=min(seg[node<<1].v,seg[node<<1|1].v);}void pushdown(int node){    if(seg[node].lazy)    {        seg[node<<1].lazy+=seg[node].lazy;        seg[node<<1|1].lazy+=seg[node].lazy;        seg[node<<1].v+=seg[node].lazy;        seg[node<<1|1].v+=seg[node].lazy;        seg[node].lazy=0;    }    return ;}void build(int l,int r,int node,double k){    seg[node].l=l;seg[node].r=r;seg[node].lazy=0;    if(l==r){        seg[node].v=k*l*1.0;        return ;    }    int mid=(l+r)/2;    build(l,mid,node<<1,k);    build(mid+1,r,node<<1|1,k);    pushup(node);    return ;}void update(int l,int r,int node,double k){    if(seg[node].l>=l&&seg[node].r<=r)    {        seg[node].v+=k;        seg[node].lazy+=k;        return ;    }    pushdown(node);    int mid = (seg[node].l+seg[node].r)/2;    if(l<=mid)    update(l,r,node<<1,k);    if(r>mid)    update(l,r,node<<1|1,k);    pushup(node);}double query(int l,int r,int node){    if(seg[node].l>=l&&seg[node].r<=r)    {        return seg[node].v;    }    pushdown(node);    int mid=(seg[node].l+seg[node].r)/2;    double xx=1e9;    if(l<=mid)    xx=min(xx,query(l,r,node<<1));    if(r>mid)    xx=min(xx,query(l,r,node<<1|1));    pushup(node);    return xx;}int main(){    int t,n;    scanf("%d",&t);    while(t--)    {        scanf("%d",&n);        mem(pos,0);        for(int i=1;i<=n;i++)        {            scanf("%d",&a[i]);            if(pos[a[i]])            pre[i]=pos[a[i]];            else pre[i]=0;            pos[a[i]]=i;        }        double l=0,r=1.0,mid,ans;        while(r-l>esp)        {            mid=(l+r)/2.0;            build(1,n,1,mid);            int flg=0;            for(int i=1;i<=n;i++)            {                update(pre[i]+1,i,1,1.0);/* ****** */                if(query(1,i,1)<=mid*(i+1.0)){flg=1;break;}            }            if(flg){ans=mid;r=mid-esp;}            else l=mid+esp;        }        printf("%lf\n",ans);    }    return 0;}


原创粉丝点击