Dirt Ratio
Time Limit: 18000/9000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 1740 Accepted Submission(s): 801
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
题意:给出n个数字,找出一个区间,使得区间内数字种类/区间长度的值最小
解题思路:二分+线段树。二分答案,每次检查用线段树。cnt(l,r)/(r-l+1)≤mid,也就是cnt(l,r)+mid*l<=mid*(r+1),每次检查线段树保存的是cnt(l,r)+mid*l,枚举r,r加入带来了自己颜色的贡献,用一个数组记录下这个颜色上一次出现的位置,在相应的区间加上这个颜色的贡献就好了。然后询问[1,i]的最值,就是当前端点作为右端点r时可以得到的最值
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <functional>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;
int n,a[600009],lazy[600009<<2],pre[600009];
double mi[600009<<2];
void build(int k,int l,int r,double val)
{
lazy[k]=0;
if(l==r) {mi[k]=l*val;return ;}
int mid=(l+r)>>1;
build(k<<1,l,mid,val),build(k<<1|1,mid+1,r,val);
mi[k]=min(mi[k<<1],mi[k<<1|1]);
}
void Push(int k,int l,int r)
{
lazy[l]+=lazy[k],lazy[r]+=lazy[k];
mi[l]+=lazy[k],mi[r]+=lazy[k];
lazy[k]=0;
}
void update(int k,int l,int r,int ll,int rr)
{
if(l>=ll&&r<=rr) {mi[k]++,lazy[k]++;return ;}
int mid=(l+r)>>1;
if(lazy[k]) Push(k,k<<1,k<<1|1);
if(mid>=ll) update(k<<1,l,mid,ll,rr);
if(rr>mid) update(k<<1|1,mid+1,r,ll,rr);
mi[k]=min(mi[k<<1],mi[k<<1|1]);
}
double query(int k,int l,int r,int rr)
{
if(rr>=r) return mi[k];
int mid=(l+r)>>1;
double ans=INF;
if(lazy[k]) Push(k,l,r);
ans=min(ans,query(k<<1,l,mid,rr));
if(rr>mid) ans=min(ans,query(k<<1|1,mid+1,r,rr));
return ans;
}
bool check(double k)
{
memset(pre,0,sizeof pre);
build(1,1,n,k);
for(int i=1;i<=n;i++)
{
update(1,1,n,pre[a[i]]+1,i);
double x=query(1,1,n,i);
if(x<=k*(i+1)) return 1;
pre[a[i]]=i;
}
return 0;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
double l=0,r=1;
while(fabs(r-l)>1e-10)
{
double mid=(l+r)/2;
if(check(mid)) r=mid;
else l=mid;
}
printf("%.10lf\n",r);
}
return 0;
}