HDU 6070 Dirt Ratio(二分+线段树)

来源:互联网 发布:solaris系统 知乎 编辑:程序博客网 时间:2024/06/06 04:13

Description
给出n次提交的题目编号,对于一个区间,假设该区间中每个题的最后一次提交是AC,之前都是WA,求所有区间中AC数/提交次数最小值
Input
第一行一整数T表示用例组数,每组用例首先输入一整数n表示总提交次数,之后n个整数a[1]~a[n]表示这n次提交的题目编号(1<=T<=15,1<=n<=6e4,1<=a[i]<=n)
Output
输出AC数/提交次数的最小值
Sample Input
1
5
1 2 1 2 3
Sample Output
0.5000000000
Solution
二分答案,设二分值为mid,num(l,r)表示区间[l,r]中的不同编号的题目数(即为AC数),那么只要存在一个区间[l,r]满足num(l,r)/(r-l+1)<=mid那么说明该二分值合法,可以寻求更小的二分值当答案,否则要找更大的二分值去找合法解,对上式转化一下变成num(l,r)+mid*l<=mid*(r+1),当区间右端点由r-1变成r时,所有num(l,r)中只有num(pre(a[r])+1,r)~num(r,r)加一,其他的均不变(pre(a[r])表示a[r]上一次出现的位置,如果a[r]没有出现则pre(a[r])=0),故可以用线段树维护num(l,r)+mid*l的最小值,每次插入的时候对pre(a[r])+1~r做区间加一操作,每次判合法只需将区间1~r中最小值拿出来和mid*(r+1)比较即可,由于精度要求是1e-4,所以二分14次即可,时间复杂度O(14nlogn)
Code

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;namespace fastIO {    #define BUF_SIZE 100000    //fread -> read    bool IOerror=0;    inline char nc()     {        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;        if(p1==pend)         {            p1=buf;            pend=buf+fread(buf,1,BUF_SIZE,stdin);            if(pend==p1)             {                IOerror=1;                return -1;            }        }        return *p1++;    }    inline bool blank(char ch)     {        return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';    }    inline void read(int &x)     {        char ch;        while(blank(ch=nc()));        if(IOerror)return;        for(x=ch-'0';(ch=nc())>='0'&&ch<='9';x=x*10+ch-'0');    }    #undef BUF_SIZE};using namespace fastIO;const int INF=1e9,maxn=60001;#define ls (t<<1)#define rs ((t<<1)|1)double Min[maxn<<2];int Lazy[maxn<<2];void push_up(int t){    Min[t]=min(Min[ls],Min[rs]);}void build(int l,int r,int t,double x){    Lazy[t]=0;    if(l==r)    {        Min[t]=x*l;        return ;    }    int mid=(l+r)/2;    build(l,mid,ls,x),build(mid+1,r,rs,x);    push_up(t);}void push_down(int t){    if(Lazy[t])    {        Lazy[ls]+=Lazy[t],Min[ls]+=Lazy[t],        Lazy[rs]+=Lazy[t],Min[rs]+=Lazy[t];        Lazy[t]=0;    }}void update(int L,int R,int l,int r,int t,int v){    if(L<=l&&r<=R)    {        Lazy[t]+=v,Min[t]+=v;        return ;    }    push_down(t);    int mid=(l+r)/2;    if(L<=mid)update(L,R,l,mid,ls,v);    if(R>mid)update(L,R,mid+1,r,rs,v);    push_up(t); }double query(int L,int R,int l,int r,int t){    if(L<=l&&r<=R)return Min[t];    push_down(t);    int mid=(l+r)/2;    double ans=INF;    if(L<=mid)ans=min(ans,query(L,R,l,mid,ls));    if(R>mid)ans=min(ans,query(L,R,mid+1,r,rs));    return ans;}int T,n,a[maxn],pre[maxn],pos[maxn];bool check(double x){    build(1,n,1,x);    for(int i=1;i<=n;i++)    {        update(pre[i]+1,i,1,n,1,1);        if(query(1,i,1,n,1)<=x*(i+1))return 1;    }    return 0;}int main(){    read(T);    while(T--)    {        read(n);        memset(pos,0,sizeof(pos));        for(int i=1;i<=n;i++)        {            read(a[i]);            pre[i]=pos[a[i]],pos[a[i]]=i;        }        double l=0,r=1,mid;        int t=14;        while(t--)        {            mid=0.5*(l+r);            if(check(mid))r=mid;            else l=mid;        }        printf("%.5f\n",mid);    }     return 0;}
原创粉丝点击