Problem Description
In ACM/ICPC contest, the ''Dirt Ratio'' of a team is calculated in the following way. First let's ignore all the problems the team didn't pass, assume the team passed
X
problems during the contest, and submitted
Y
times for these problems, then the ''Dirt Ratio'' is measured as
XY
. If the ''Dirt Ratio'' of a team is too low, the team tends to cause more penalty, which is not a good performance.
Picture from MyICPC
Little Q is a coach, he is now staring at the submission list of a team. You can assume all the problems occurred in the list was solved by the team during the contest. Little Q calculated the team's low ''Dirt Ratio'', felt very angry. He wants to have a talk with them. To make the problem more serious, he wants to choose a continuous subsequence of the list, and then calculate the ''Dirt Ratio'' just based on that subsequence.
Please write a program to find such subsequence having the lowest ''Dirt Ratio''.
Picture from MyICPC
Little Q is a coach, he is now staring at the submission list of a team. You can assume all the problems occurred in the list was solved by the team during the contest. Little Q calculated the team's low ''Dirt Ratio'', felt very angry. He wants to have a talk with them. To make the problem more serious, he wants to choose a continuous subsequence of the list, and then calculate the ''Dirt Ratio'' just based on that subsequence.
Please write a program to find such subsequence having the lowest ''Dirt Ratio''.
Input
The first line of the input contains an integer
T(1≤T≤15)
, denoting the number of test cases.
In each test case, there is an integer n(1≤n≤60000) in the first line, denoting the length of the submission list.
In the next line, there are n positive integers a1,a2,...,an(1≤ai≤n) , denoting the problem ID of each submission.
In each test case, there is an integer n(1≤n≤60000) in the first line, denoting the length of the submission list.
In the next line, there are n positive integers a1,a2,...,an(1≤ai≤n) , denoting the problem ID of each submission.
Output
For each test case, print a single line containing a floating number, denoting the lowest ''Dirt Ratio''. The answer must be printed with an absolute error not greater than
10−4
.
Sample Input
1 5 1 2 1 2 3
Sample Output
0.5000000000
题目等同于给你一串01序列,让你找出平均值最小的子串
平均值不是特别好处理。我们考虑求平均值的式子sigmaXi/n=x
即sigmaXi=nx
sigma(Xi-x)=0
那么我们就可以二分平均数,然后把每个数都减去这个平均数,那么就相当于询问区间最小值是否小于0
那么1和0就转换成了1-x和-x。
因为题目中对于相同的题目取最右边的那个1,因此我们枚举右端点,每次把该题前一次通过的位置改成0
每次枚举右端点我们维护所有左端点到当前右端点的区间和存在左端点上,那么如果找到有值<0即说明当前二分的答案可以达到
#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
double eps=1e-7;
struct tree
{
int l,r;
double mi;
double tag;
}tr[800001];
int n;
inline void up(int p)
{
tr[p].mi=min(tr[p*2].mi,tr[p*2+1].mi);
}
inline void push(int p)
{
tr[p*2].mi+=tr[p].tag;
tr[p*2+1].mi+=tr[p].tag;
tr[p*2].tag+=tr[p].tag;
tr[p*2+1].tag+=tr[p].tag;
tr[p].tag=0;
}
inline void build(int p,int l,int r)
{
tr[p].l=l;
tr[p].r=r;
tr[p].mi=tr[p].tag=0;
if(l!=r)
{
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
up(p);
}
}
inline void add(int p,int l,int r,double xx)
{
if(l>r)
return ;
if(l<=tr[p].l&&tr[p].r<=r)
{
tr[p].mi+=xx;
tr[p].tag+=xx;
}
else
{
push(p);
int mid=(tr[p].l+tr[p].r)/2;
if(l<=mid)
add(p*2,l,r,xx);
if(r>mid)
add(p*2+1,l,r,xx);
up(p);
}
}
inline double ask(int p,int l,int r)
{
if(l<=tr[p].l&&tr[p].r<=r)
return tr[p].mi;
else
{
push(p);
int mid=(tr[p].l+tr[p].r)/2;
double ans=2100000000;
if(l<=mid)
ans=min(ans,ask(p*2,l,r));
if(r>mid)
ans=min(ans,ask(p*2+1,l,r));
return ans;
}
}
int a[60011];
int la[60011];
int pre[600011];
inline bool check(double lim)
{
build(1,1,n);
bool flag=false;
int i;
for(i=1;i<=n;i++)
{
add(1,1,i,(double)1-lim);
add(1,1,pre[i],-1);
if(ask(1,1,i)<=0)
return true;
}
return false;
}
int main()
{
int T;
scanf("%d",&T);
while(T>0)
{
T--;
scanf("%d",&n);
memset(la,0,sizeof(la));
int i;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
pre[i]=la[a[i]];
la[a[i]]=i;
}
double l=0,r=1;
while(l+eps<r)
{
double mid=(l+r)/(double)2;
if(check(mid))
r=mid;
else
l=mid;
}
printf("%.8f\n",r);
}
}