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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hfuu1504011020/article/details/76695127

题意:就是要我们求一个区间不同种类的个数与该区间的长度的比值,然后取比值最小值。
思想:比赛时想到用线段树去处理他,与平时写的线段树它的维护区间有很多差别,之后实在没法去维护就放弃了,之后看了题解,又看了一些博客,总算了解了它是如何维护区间值。首先我们可以二分答案最小比值,然后根据二分的答案乘以它的个数此时得到的就是种类数,然后我们对种类数进行维护,由于种类数受个数增加的影响,但每次移动我们加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 0x3f3f3f3f
int 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

猜你喜欢

转载自blog.csdn.net/hfuu1504011020/article/details/76695127
今日推荐