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);
}
}