Dirt Ratio
Time Limit: 18000/9000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
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''.
![](http://acm.hdu.edu.cn/data/images/C762-1004-1.jpg)
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
对于区间[L ,R] ,不同数有X个, f = X/(R-L+1) , 求最小的f 。
首先二分f
对于给定的f ,
枚举右端点r 。 有 X / (r-l+1) <= f
X + l * f <= (r+1) * f
这里对于给定的r , (r+1)*f 为定值。
转换为寻找最小的X+l*f
对于不同的左端点,其实l*f 也是定值。
转换为维护X的值,即:维护[1,r] ,[2,r],[3,r]....[r,r]区间不同数的个数,可用线段树来维护。
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) {
new Task().solve();
}
}
class Task {
InputReader in = new InputReader(System.in) ;
PrintWriter out = new PrintWriter(System.out) ;
int n ;
int[] num ;
double[] min , add ;
int[] last = new int[60008] ;
void build(int l , int r , int t , double mid){
add[t] = 0 ;
if(l == r){
min[t] = l * mid ;
return ;
}
int m = (l + r) >> 1 ;
build(l, m, t<<1 , mid) ;
build(m+1, r, t<<1|1 , mid) ;
up(t) ;
}
void down(int t){
if(add[t] != 0){
add[t<<1] += add[t] ;
add[t<<1|1] += add[t] ;
min[t<<1] += add[t] ;
min[t<<1|1] += add[t] ;
add[t] = 0 ;
}
}
void up(int t){
min[t] = Math.min(min[t<<1] , min[t<<1|1]) ;
}
void update(int L , int R , double d , int l , int r , int t){
if(L <= l && r <= R){
min[t] += d ;
add[t] += d ;
return ;
}
down(t) ;
int m = (l + r) >> 1 ;
if(L <= m){
update(L, R, d, l, m, t<<1) ;
}
if(R > m){
update(L, R, d, m+1, r, t<<1|1) ;
}
up(t) ;
}
double query(int L , int R , int l , int r , int t){
if(L <= l && r <= R){
return min[t] ;
}
down(t) ;
int m = (l + r) >> 1 ;
double reslut = Double.MAX_VALUE ;
if(L <= m){
reslut = Math.min(reslut, query(L, R, l, m, t<<1)) ;
}
if(R > m){
reslut = Math.min(reslut, query(L, R, m+1, r, t<<1|1)) ;
}
up(t) ;
return reslut ;
}
boolean judge(double mid){
Arrays.fill(last, 0) ;
build(1, n, 1 , mid) ;
for(int r = 1 ; r <= n ; r++){
update(last[num[r]]+1, r, 1 , 1 , n , 1) ;
double q = query(1, r, 1, n, 1) ;
if(q <= mid * (r+1)){
return true ;
}
last[num[r]] = r ;
}
return false ;
}
void solve(){
int t = in.nextInt() ;
while(t-- > 0){
n = in.nextInt() ;
num = new int[n+1] ;
min = new double[n<<2] ;
add = new double[n<<2] ;
for(int i = 1 ; i <= n ; i++){
num[i] = in.nextInt() ;
}
double l = 0.0 , r = 1.0 , result = -1 ;
for(int step = 0 ; step < 20 ; step++){
double mid = (l + r) * 0.5 ;
if(judge(mid)){
r = mid ;
result = mid ;
}
else{
l = mid ;
}
}
out.printf("%.10f%n" , result) ;
}
out.flush() ;
}
}
class InputReader {
public BufferedReader reader;
public StringTokenizer tokenizer;
public InputReader(InputStream stream) {
reader = new BufferedReader(new InputStreamReader(stream), 32768);
tokenizer = new StringTokenizer("");
}
private void eat(String s) {
tokenizer = new StringTokenizer(s);
}
public String nextLine() {
try {
return reader.readLine();
} catch (Exception e) {
return null;
}
}
public boolean hasNext() {
while (!tokenizer.hasMoreTokens()) {
String s = nextLine();
if (s == null)
return false;
eat(s);
}
return true;
}
public String next() {
hasNext();
return tokenizer.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public int[] nextInts(int n) {
int[] nums = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = nextInt();
}
return nums;
}
public long nextLong() {
return Long.parseLong(next());
}
public double nextDouble() {
return Double.parseDouble(next());
}
public BigInteger nextBigInteger() {
return new BigInteger(next());
}
}
转换