HDU 6070 Dirt Ratio

来源:互联网 发布:璟璞网络福利员 编辑:程序博客网 时间:2024/05/22 01:49

2017多校4-4 Dirt Ratio

线段树,二分法

题意

给你一个数列,求一个子区间,使得:区间内不同数字种类/区间内所有数字个数最小。输出最小值。

思路

二分答案mid,检验是否存在一个区间满足size(l,r)rl+1mid,也就是size(l,r)+mid×lmid×(r+1)
从左往右枚举每个位置作为r,当r变化为r+1时,对size的影响是一段区间加1,线段树维护区间最小值即可。
时间复杂度O(nlognlogw)

每次二分,都重建线段树,叶子初始化为mid*l。线段树每个叶子tree[i]维护是:i到当前枚举位置 这个区间内有多少个不同的数字。
所以二分后针对每个右端点i,与其值a[i],区间更新a[i]上一次出现位置la[a[i]]到i,区间加1,代表这些区间新出现了a[i]这个值。
然后线段树维护区间最小值,每次查询就得出了所有左端点小于当前枚举的位置、构成的所有合法区间,出现不同数字最少的区间。

代码

#include<bits\stdc++.h>#define M(a,b) memset(a,b,sizeof(a))#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1using namespace std;const int MAXN=500005;struct STree{    double val;int lazy;}stree[MAXN];int a[MAXN], la[MAXN];void pushup(int rt){    stree[rt].val=min(stree[rt<<1].val, stree[rt<<1|1].val);}void pushdown(int rt){    if(stree[rt].lazy)    {        stree[rt<<1].val+=stree[rt].lazy;        stree[rt<<1|1].val+=stree[rt].lazy;        stree[rt<<1].lazy+=stree[rt].lazy;        stree[rt<<1|1].lazy+=stree[rt].lazy;        stree[rt].lazy=0;    }}void build(int l, int r, int rt, double k){    stree[rt].lazy=0;    if(l==r)    {        stree[rt].val=k*l;        return;    }    int m=(l+r)>>1;    build(lson, k);    build(rson, k);    pushup(rt);}void update(int L, int R, int l, int r, int rt){    if(L<=l&&r<=R)    {        stree[rt].val++;        stree[rt].lazy++;        return;    }    pushdown(rt);    int m=(l+r)>>1;    if(L<=m) update(L, R, lson);    if(m<R) update(L, R, rson);    pushup(rt);}double query(int L, int R, int l, int r, int rt){    if(L<=l&&r<=R) return stree[rt].val;    pushdown(rt);    int m=(l+r)>>1;    double res=1e10;    if(L<=m) res=min(res, query(L, R, lson));    if(m<R) res=min(res, query(L, R, rson));    return res;}int main(){    int T;scanf("%d", &T);    while(T--)    {        int n;scanf("%d", &n);        for(int i=1;i<=n;i++)            scanf("%d", &a[i]);        double l=0.0, r=1.0;int tim=20;        while(tim--)        {            double mid=(l+r)/2.0;            build(1, n, 1, mid);            M(la, 0);            bool fl=0;            for(int i=1;i<=n&&!fl;i++)            {                update(la[a[i]]+1, i, 1, n, 1);                la[a[i]]=i;                if(query(1, i, 1, n, 1)<=mid*(i+1)) fl=1;            }            if(fl) r=mid;            else l=mid;        }        printf("%.10lf\n", l);    }}