Hdu-6070 divide rati line tree + fractional programming

Posted by mjm7867 on Sun, 03 May 2020 12:42:18 +0200

Title:
Give you an array, find an interval to minimize the ratio of the number of different numbers in the interval to the length of the interval.

Solution:
This is a classic score planning problem. Considering the dichotomy answer K, our goal is to find an interval to make Val / len < = k, Val is the number of different numbers in the interval, len is the length of the interval. After transformation, we can get val-k * len < = 0. We can use the line tree to achieve the effect of fast query: maintain the minimum value of the interval, pre[a[i]] records the number of a[i] in the previous record For the position of [pre[i]+1,i] interval + 1, [1,i] interval - K, the minimum value of [1,i] interval shall be calculated after each operation. If it is less than 0, it means that the condition is met.

code:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=60010;
struct tree{
    int l,r;
    double v,tag;
}tr[4*N];
int n,T,a[N];
int pre[N];
const double eps=1e-6;
void update(int i)
{
    tr[i].v=min(tr[i<<1].v,tr[i<<1|1].v);
} 
void build(int i,int l,int r)
{
    tr[i].l=l;tr[i].r=r;tr[i].v=0;tr[i].tag=0;
    if (l==r) return;
    int mid=l+r>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
}
void add(int i,double x)
{
    tr[i].tag+=x;
    tr[i].v+=x;
}
void pushdown(int i)
{
    if (tr[i].tag)
    {
        if (tr[i].l==tr[i].r) {tr[i].tag=0;return;} 
        add(i<<1,tr[i].tag);
        add(i<<1|1,tr[i].tag);
        tr[i].tag=0;
    } 
}
void modify(int i,int l,int r,double v)
{
    int L=tr[i].l,R=tr[i].r;
    if (L>r||l>R) return;
    if (l<=L&&R<=r) {add(i,v);return;}
    pushdown(i);
    modify(i<<1,l,r,v);
    modify(i<<1|1,l,r,v);
    update(i);
}
double query(int i,int l,int r)
{
    int L=tr[i].l,R=tr[i].r;
    if (L>r||l>R) return 1e9;
    if (l<=L&&R<=r) return tr[i].v;
    pushdown(i);
    double ans=1e9;
    ans=min(ans,query(i<<1,l,r));
    ans=min(ans,query(i<<1|1,l,r));
    return ans;
}
bool solve(double k)
{
    build(1,1,n);
    memset(pre,0,sizeof(pre));
    for (int i=1;i<=n;i++)
    {
        modify(1,pre[a[i]]+1,i,1);
        modify(1,1,i,-k);
        if (query(1,1,i)<=0) return 1;
        pre[a[i]]=i;
    }
    return 0;
}
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        double l=0,r=1,ans=1;
        while (r-l>=eps)
        {
            double mid=(l+r)/2;
            if (solve(mid)) ans=mid,r=mid;
            else l=mid;
        }
        printf("%.5f\n",ans);
    }
}

Topics: less