HDU6070 2017杭电多校联赛第四场-Dirt Ratio

来源:互联网 发布:橙光制作工具 mac 编辑:程序博客网 时间:2024/05/16 17:51

题意:就是要我们求一个区间不同种类的个数与该区间的长度的比值,然后取比值最小值。
思想:比赛时想到用线段树去处理他,与平时写的线段树它的维护区间有很多差别,之后实在没法去维护就放弃了,之后看了题解,又看了一些博客,总算了解了它是如何维护区间值。首先我们可以二分答案最小比值,然后根据二分的答案乘以它的个数此时得到的就是种类数,然后我们对种类数进行维护,由于种类数受个数增加的影响,但每次移动我们加1,再然后我们就去更新这个区间的最小值,确定最小值后(即该区间的种类个数),判断最小值减去(二分时的答案乘以此时右移的个数)是否小于eps,剩余的就是二分的过程。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>using namespace std;const int MAX=6e4+10;const double eps=1e-5;#define INF 0x3f3f3f3fint T;int n;int a[MAX<<2],q[MAX<<2],p[MAX<<2];double sum[MAX<<2];int vis[MAX<<2];void pushup(int cur){    sum[cur]=min(sum[cur<<1],sum[cur<<1|1]);}void pushdown(int cur){    if(vis[cur])    {        sum[cur<<1]+=vis[cur];        sum[cur<<1|1]+=vis[cur];        vis[cur<<1]+=vis[cur];        vis[cur<<1|1]+=vis[cur];        vis[cur]=0;        return ;    }}void build(int cur,int l,int r,int id,double x){    if(l==r)    {        sum[cur]=l*x;        return ;    }    int mid=l+r>>1;    pushdown(cur);    if(id<=mid) build(cur<<1,l,mid,id,x);    else build(cur<<1|1,mid+1,r,id,x);    pushup(cur);}void updata(int cur,int L,int R,int l,int r){    if(L<=l&&R>=r)    {        sum[cur]+=1;        vis[cur]+=1;        return ;    }    int mid=l+r>>1;    pushdown(cur);    if(mid>=L) updata(cur<<1,L,R,l,mid);    if(mid<R) updata(cur<<1|1,L,R,mid+1,r);    pushup(cur);    }int query(double x){    for(int i=1;i<MAX*4;i++) sum[i]=INF;    memset(vis,0,sizeof(vis));    for(int i=1;i<=n;i++)    {        build(1,1,n,i,x);        updata(1,p[i]+1,i,1,n);        if(sum[1]-x*(i+1)<eps) //(二分的答案乘以右移的个数)与我们更新的种类数的比较。           return 1;    }    return 0;}int main(){    while(~scanf("%d",&T))    {        while(T--)        {            scanf("%d",&n);        memset(q,0,sizeof(q));        for(int i=1;i<=n;i++)        {            scanf("%d",&a[i]);            p[i]=q[a[i]];            q[a[i]]=i;        }        double l=0,r=1,cnt=0;        while(r-l>eps)        {            double mid=(l+r)/2;            if(query(mid))            {              cnt=mid;              r=mid-eps ;              //cout<<cnt<<endl;            }            else l=mid+eps ;          //cout<<cnt<<endl;            }        printf("%.10f\n",cnt);        }    }    return 0;}

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

原创粉丝点击