看了题解才知道这怎么做,其实之前做过一道类似的线段树的题这里,但是比赛的时候还是没有做出来。
根据官方给的题解 其实我们要求的就是这个
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define clr(x) memset(x,0,sizeof(x))
using namespace std;
#define LL long long
int dat[60005];
int last[60005];
int cur[60005];
struct node
{
double cnt;
double minnum;
}tree[600005<<2];
int n;
void PushUp(int now)
{
tree[now].minnum = min(tree[now<<1].minnum,tree[now<<1|1].minnum);
}
void PushDown(int now)
{
if(tree[now].cnt!=0)
{
int lson = now << 1;
int rson = now << 1|1;
tree[lson].cnt += tree[now].cnt;
tree[rson].cnt += tree[now].cnt;
tree[lson].minnum += tree[now].cnt;
tree[rson].minnum += tree[now].cnt;
tree[now].cnt = 0;
}
}
void Update(int ul,int ur,int l,int r,double val,int now)
{
if(ul<=l && r <= ur)
{
tree[now].minnum += val;
tree[now].cnt += val;
return;
}
PushDown(now);
int mid = (l+r)/2;
if(ul<=mid)
Update(ul,ur,l,mid,val,now<<1);
if(ur>mid)
Update(ul,ur,mid+1,r,val,now<<1|1);
PushUp(now);
}
double Query(int ql,int qr,int l,int r,int now)
{
if(ql<=l && r <= qr)
{
return tree[now].minnum;
}
PushDown(now);
double a1,a2;
a1 = a2 = 99999999;
int mid = (l+r)/2;
if(ql<=mid)
{
a1 = Query(ql,qr,l,mid,now<<1);
}
if(qr>mid)
{
a2 =Query(ql,qr,mid+1,r,now<<1|1);
}
return min(a1,a2);
}
bool judge(double p)
{
clr(tree);
for(int i = 1;i<=n;i++)
{
Update(i,i,1,n,p*i,1);
}
for(int i = 1;i<=n;i++)
{
Update(last[i]+1,i,1,n,1,1);
double q = Query(0,i,1,n,1);
if(q<(i+1)*p)
{
return true;
}
}
return false;
}
double GetAns()
{
double s = 0;
double e = 1;
double mid;
for(int i = 0;i<20;i++)
{
mid = (s+e)/2;
//cout << s << " " << e << endl;
if(judge(mid))
{
e = mid;
}
else
s = mid;
}
return mid;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
clr(last);
clr(cur);
for(int i = 1;i<=n;i++)
{
scanf("%d",&dat[i]);
last[i] = cur[dat[i]];
cur[dat[i]] = i;
}
double ans = GetAns();
printf("%.9lf\n",ans);
}
return 0;
}