---------题目链接,戳这里------------
题目意思:
题目一通描述,弄得我完全懵逼。幸好讨论区,有题目意思。
题目意思为:定义f(l,r) 为区间 [l,r] 的不同元素个数/区间长度。求最小的 f(l,r) 定义域:\(0 < l \leqslant r \leqslant n\)。题目意思,翻译转一下就是这么简单。
思路:
思路就是,官方题解给出的,二分+线段树;我们二分答案,mid。需要判断mid是否满足,假设我们定义 \(size\left ( l,r \right )\)为区间 [l,r] 的不同元素个数。那么就需要mid满足:\(\frac{size\left ( l,r \right )}{r-l+1}\leq mid\),按照题解进行变形式子可以得到:\(size \left ( l,r \right )+ mid \times l \leq mid \times \left ( r+1 \right )\),我们可以对r进行从左到右的枚举。在每一次枚举中r就是一个常数。我们可以用线段树维护区间最小值,维护 \(size \left ( l,r \right )+ mid \times l\) ,每次r+1,需要更新r,r这个区间,区间加mid×r。还有需要给r区间到之前出现a[r]位置的右边这个区间的size都会加1。所以两次更新,每次我们需要查询区间 [1,r] 的区间最小值。先写一个区间维护最小值的插线问线的线段树。进行二分 。over;二分的时候,如果满足条件说明mid还不是最小的所以把上限\(r = mid\),否则下限\(l = mid\);
代码比较搓。还好能够AC (-.-)
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <time.h>
using namespace std;
typedef long long LL;
const LL INF = 2e9 + 1e8;
const double eps = 0.0000000001;
void fre()
{
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
}
#define MSET(a, b) memset(a, b, sizeof(a))
const int MOD = 1e9 + 7;
const int maxn = 1e6 + 100;
int a[maxn], pre[maxn], pos[maxn];
struct nyist
{
double tree[maxn], lazy[maxn];
void init()
{
MSET(tree, 0);
MSET(lazy, 0);
}
void pushdown(int i)
{
if (lazy[i] > eps)
{
tree[i << 1] += lazy[i], tree[i << 1 | 1] += lazy[i];
lazy[i << 1] += lazy[i], lazy[i << 1 | 1] += lazy[i];
lazy[i] = 0;
}
}
void update(int i, int l, int r, int L, int R, double k)
{
if (L == l && R == r)
{
tree[i] += k;
lazy[i] += k;
return;
}
pushdown(i);
int mid = (l + r) >> 1;
if (R <= mid)
update(i << 1, l, mid, L, R, k);
else if (L > mid)
update(i << 1 | 1, mid + 1, r, L, R, k);
else
update(i << 1, l, mid, L, mid, k), update(i << 1 | 1, mid + 1, r, mid + 1, R, k);
tree[i] = min(tree[i << 1], tree[i << 1 | 1]);
}
double query(int i, int l, int r, int L, int R)
{
if (L == l && r == R)
return tree[i];
pushdown(i);
int mid=(l+r)>>1;
if(R<=mid) return query(i<<1,l,mid,L,R);
else if(L>mid) return query(i<<1|1,mid+1,r,L,R);
else return min(query(i<<1,l,mid,L,mid),query(i<<1|1,mid+1,r,mid+1,R));
}
} ac;
int main()
{
int ncase;
scanf("%d", &ncase);
while (ncase--)
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
MSET(pos,0);
for (int i = 1; i <= n; i++)
{
pre[i]=pos[a[i]];
pos[a[i]]=i;
}
double l = 0, r = 1.0,res;
while (fabs(l-r)>eps)
{
ac.init();
double mid = (l + r) / 2;
bool flag = false;
for (int i = 1; i <= n; i++)
{
ac.update(1, 1, n, i, i, mid *i);
ac.update(1,1,n,pre[i]+1,i,1.0);
double ans=ac.query(1,1,n,1,i);
if(ans<=mid*(i+1))
{
flag=true;
break;
}
}
if(flag) r=mid,res=mid;
else l=mid;
}
printf("%lf\n",res);
}
return 0;
}