Dirt Ratio
Time Limit: 18000/9000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 1104 Accepted Submission(s): 486
Special Judge
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.5000000000HintFor every problem, you can assume its final submission is accepted.
Source
Recommend
题意:给n个数,设x/y为区间内不同数的个数除以区间长度,问x/y的最小值。
题解:二分答案x/y,当我们去检验mid的时候,会得到如下表达式(size表示区间不同数的个数)
之后我们对表达式进行转换
这样我们就可以根据如上表达式判断mid是否合法。我们每次枚举右端点,当新加入一个点的时候,我们需要对不包含这个数的最右的连续区间进行整体加1,这时候我们就可以,用线段树来维护区间最小值,线段树上的每一个叶子节点表示,size(l,r)+mid*l 。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <string.h>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <list>
#include <bitset>
#include <stack>
#include <stdlib.h>
#define lowbit(x) (x&-x)
#define e exp(1.0)
#define eps 1e-8
//ios::sync_with_stdio(false);
// auto start = clock();
// cout << (clock() - start) / (double)CLOCKS_PER_SEC;
typedef long long ll;
typedef long long LL;
using namespace std;
//维护size(l,r)+mid*l<=mid*(r+1)
const int maxn=60006;
double tree[maxn<<2],add[maxn<<2];
int last[maxn];
int a[maxn];
void pushdown(int root)
{
tree[root<<1]+=add[root];
tree[root<<1|1]+=add[root];
add[root<<1]+=add[root];
add[root<<1|1]+=add[root];
add[root]=0;
}
void update(int l,int r,int L,int R,int root,double k)
{
if(l<=L && r>=R)
{
tree[root]+=k;
add[root]+=k;
return ;
}
if(add[root]>eps)
pushdown(root);
int mid=(L+R)/2;
if(r<=mid) update(l,r,L,mid,root<<1,k);
else if(l>mid) update(l,r,mid+1,R,root<<1|1,k);
else
{
update(l,mid,L,mid,root<<1,k);
update(mid+1,r,mid+1,R,root<<1|1,k);
}
tree[root]=min(tree[root<<1],tree[root<<1|1]);
}
double query(int l,int r,int L,int R,int root)
{
if(l<=L && r>=R) return tree[root];
if(add[root]>eps) pushdown(root);
int mid=(L+R)/2;
if(r<=mid)return query(l,r,L,mid,root<<1);
else if(l>mid)return query(l,r,mid+1,R,root<<1|1);
else return min(query(l,mid,L,mid,root<<1),query(mid+1,r,mid+1,R,root<<1|1));
tree[root]=min(tree[root<<1],tree[root<<1|1]);
}
int main()
{
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
double l=0,r=1;
for(int bin=0;bin<20;bin++)
{
double mid=(l+r)/2.0;
memset(tree,0,sizeof(tree));
memset(add,0,sizeof(add));
memset(last,0,sizeof(last));
int flag=0;
for(int i=1;i<=n;i++)
{
update(last[a[i]]+1,i,1,n,1,1);
update(i,i,1,n,1,mid*i);
last[a[i]]=i;
double k=query(1,i,1,n,1);
if(k<=(double)mid*(i+1))
{
flag=1;
break;
}
}
if(!flag) l=mid;
else r=mid;
}
printf("%.4f\n",r);
}
return 0;
}