Dirt Ratio
Time Limit: 18000/9000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 1339 Accepted Submission(s): 605
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
X
Y![]()
![]()
. 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''.
![](https://i-blog.csdnimg.cn/blog_migrate/82117ccf81ad234689184de180a8399d.jpeg)
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
a
1
,a
2
,...,a
n
(1≤a
i
≤n)
, denoting the problem ID of each submission.
In each test case, there is an integer n(1≤n≤60000)
In the next line, there are n
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的序列,编号相同代表颜色一样,选择一段序列使得颜色数 / 该段总数最小
题解:可以考虑二分,设当前最小值为mid,该段总数为r-l+1,颜色数为size(l,r),则该段的比值需要满足:
size(l,r)/(r−l+1) ≤ mid,
也就是 size(l, r) + mid × l ≤mid × (r + 1)。剩下的问题就很好解决了,直接枚举区间右端点即可,
在每一次枚举中r就是一个常数,首先将r加入到[r,r]的区间内,然后更新r到上一次出现r的位置这一区间,我们可以用线段树维护区间最小值,线段树上的每一个点代表不等式左边的表达式。
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<math.h>
#include<time.h>
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
typedef long long ll;
#define inf 2147483647
#define mod 998244353
#define maxn 200005
#define lowbit(x) (x&-x)
#define eps 1e-6
double mins[maxn];
int p[maxn],a[maxn],pos[maxn],n,lazy[maxn];
void pushdown(int id)
{
if(lazy[id]>eps)
{
mins[id*2]+=lazy[id];
mins[id*2+1]+=lazy[id];
lazy[id*2]+=lazy[id];
lazy[id*2+1]+=lazy[id];
lazy[id]=0;
}
}
void updata(int id,int l,int r,int a,int b,double x)
{
if(r<a || l>b)
return;
if(l>=a && r<=b)
{
mins[id]+=x;
lazy[id]+=x;
return;
}
pushdown(id);
int m=(l+r)/2;
if(a<=m)
updata(id*2,l,m,a,b,x);
if(b>m)
updata(id*2+1,m+1,r,a,b,x);
mins[id]=min(mins[id*2],mins[id*2+1]);
}
double query(int id,int l,int r,int a,int b)
{
if(r<a || l>b)
return 100000000.0;
if(l>=a && r<=b)
return mins[id];
int m=(l+r)/2;
double res=10000000.0;
pushdown(id);
if(a<=m)
res=min(res,query(id*2,l,m,a,b));
if(b>m)
res=min(res,query(id*2+1,m+1,r,a,b));
mins[id]=min(mins[id*2],mins[id*2+1]);
return res;
}
int main(void)
{
int T,i,j;
double l,r,mid,tmp=0;
scanf("%d",&T);
while(T--)
{
memset(p,0,sizeof(p));
memset(pos,0,sizeof(pos));
double ans=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
p[i]=pos[a[i]];
pos[a[i]]=i;
}
l=0;r=1.0;
while(fabs(r-l)>eps)
{
memset(mins,0,sizeof(mins));
memset(lazy,0,sizeof(lazy));
mid=(l+r)/2.0;bool flag=0;
for(i=1;i<=n;i++)
{
updata(1,1,n,i,i,mid*i);
updata(1,1,n,p[i]+1,i,1.0);
tmp=query(1,1,n,1,i);
if(tmp<=mid*(i+1))
{
flag=1;
break;
}
}
if(flag)
r=mid,ans=mid;
else
l=mid;
}
printf("%.10f\n",ans);
}
}